aboutsummaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2023-03-16 14:55:22 +0100
committerMartin Polden <mpolden@mpolden.no>2023-03-23 12:13:16 +0100
commite45060cb75d78c10feae13b9344722d6fe99ffe8 (patch)
treefb530b21b3e95e0bd553b588e3200d9c9d7289a2 /client
parent5d83a7b7c3ecd8dc5f1bd4e307cb75d9b69bc170 (diff)
Model result of a feeding operation
Diffstat (limited to 'client')
-rw-r--r--client/go/internal/vespa/feed/feed.go35
-rw-r--r--client/go/internal/vespa/feed/http.go42
-rw-r--r--client/go/internal/vespa/feed/http_test.go9
3 files changed, 74 insertions, 12 deletions
diff --git a/client/go/internal/vespa/feed/feed.go b/client/go/internal/vespa/feed/feed.go
new file mode 100644
index 00000000000..d042544ae75
--- /dev/null
+++ b/client/go/internal/vespa/feed/feed.go
@@ -0,0 +1,35 @@
+package feed
+
+type Status int
+
+const (
+ // StatusSuccess indicates a successful document operation.
+ StatusSuccess Status = iota
+ // StatusConditionNotMet indicates that the document operation itself was successful, but did not satisfy its
+ // test-and-set condition.
+ StatusConditionNotMet
+ // StatusVespaFailure indicates that Vespa failed to process the document operation.
+ StatusVespaFailure
+ // StatusTransportFailure indicates that there was failure in the transport layer error while sending the document
+ // operation to Vespa.
+ StatusTransportFailure
+ // StatusError is a catch-all status for any other error that might occur.
+ StatusError
+)
+
+// Result represents the result of a feeding operation.
+type Result struct {
+ Id DocumentId
+ Status Status
+ Message string
+ Trace string
+ Err error
+}
+
+// Success returns whether status s is considered a success.
+func (s Status) Success() bool { return s == StatusSuccess || s == StatusConditionNotMet }
+
+// Feeder is the interface for code that perform a document operation and return its result.
+type Feeder interface {
+ Send(Document) Result
+}
diff --git a/client/go/internal/vespa/feed/http.go b/client/go/internal/vespa/feed/http.go
index f0b7eb42aa6..8fd892c4f46 100644
--- a/client/go/internal/vespa/feed/http.go
+++ b/client/go/internal/vespa/feed/http.go
@@ -2,6 +2,8 @@ package feed
import (
"bytes"
+ "encoding/json"
+ "fmt"
"net/http"
"net/url"
"strconv"
@@ -24,9 +26,6 @@ type ClientOptions struct {
TraceLevel *int
}
-// Result represents the result of a feeding operation
-type Result struct{}
-
func NewClient(options ClientOptions, httpClient util.HTTPClient) *Client {
return &Client{options: options, httpClient: httpClient}
}
@@ -46,20 +45,47 @@ func (c *Client) queryParams() url.Values {
}
// Send given document the URL configured in this client.
-func (c *Client) Send(document Document) (Result, error) {
+func (c *Client) Send(document Document) Result {
method, url, err := document.FeedURL(c.options.BaseURL, c.queryParams())
if err != nil {
- return Result{}, err
+ return Result{Status: StatusError, Err: err}
}
body := document.Body()
req, err := http.NewRequest(method, url.String(), bytes.NewReader(body))
if err != nil {
- return Result{}, err
+ return Result{Status: StatusError, Err: err}
}
resp, err := c.httpClient.Do(req, c.options.Timeout)
if err != nil {
- return Result{}, err
+ return Result{Status: StatusTransportFailure, Err: err}
}
defer resp.Body.Close()
- return Result{}, nil
+ return createResult(resp)
+}
+
+func createResult(resp *http.Response) Result {
+ result := Result{}
+ switch resp.StatusCode {
+ case 200:
+ result.Status = StatusSuccess
+ case 412:
+ result.Status = StatusConditionNotMet
+ case 502, 504, 507:
+ result.Status = StatusVespaFailure
+ default:
+ result.Status = StatusTransportFailure
+ }
+ var body struct {
+ Message string `json:"message"`
+ Trace json.RawMessage `json:"trace"`
+ }
+ jsonDec := json.NewDecoder(resp.Body)
+ if err := jsonDec.Decode(&body); err != nil {
+ result.Status = StatusError
+ result.Err = fmt.Errorf("failed to decode json response: %w", err)
+ return result
+ }
+ result.Message = body.Message
+ result.Trace = string(body.Trace)
+ return result
}
diff --git a/client/go/internal/vespa/feed/http_test.go b/client/go/internal/vespa/feed/http_test.go
index 5c9378ab5f7..3a00e6fffc9 100644
--- a/client/go/internal/vespa/feed/http_test.go
+++ b/client/go/internal/vespa/feed/http_test.go
@@ -14,13 +14,14 @@ import (
func TestClientSend(t *testing.T) {
doc := Document{Create: true, UpdateId: "id:ns:type::doc1", Fields: json.RawMessage(`{"foo": "123"}`)}
httpClient := mock.HTTPClient{}
- client := NewClient(ClientOptions{
+ var client Feeder = NewClient(ClientOptions{
BaseURL: "https://example.com:1337",
Timeout: time.Duration(5 * time.Second),
}, &httpClient)
- _, err := client.Send(doc)
- if err != nil {
- t.Fatalf("got unexpected error %q", err)
+ httpClient.NextResponseString(200, `{"message":"All good!"}`)
+ res := client.Send(doc)
+ if res.Err != nil {
+ t.Fatalf("got unexpected error %q", res.Err)
}
r := httpClient.LastRequest
if r.Method != http.MethodPut {