Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 36 additions & 2 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -1295,7 +1295,7 @@ func (c *HostClient) DoTimeout(req *Request, resp *Response, timeout time.Durati
func (c *HostClient) DoDeadline(req *Request, resp *Response, deadline time.Time) error {
req.timeout = time.Until(deadline)
if req.timeout <= 0 {
return ErrTimeout
return wrapErrWithUpstream(ErrTimeout, c.Addr)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious why you only wrap the error here? When someone uses this method they can just read c.Addr themselves? I thought this was about Client.RetryIfErr where you can't know the addr?

}
return c.Do(req, resp)
}
Expand Down Expand Up @@ -1374,7 +1374,7 @@ func (c *HostClient) Do(req *Request, resp *Response) error {
if timeout > 0 {
req.timeout = time.Until(deadline)
if req.timeout <= 0 {
err = ErrTimeout
err = wrapErrWithUpstream(ErrTimeout, c.Addr)
break
}
}
Expand All @@ -1393,6 +1393,9 @@ func (c *HostClient) Do(req *Request, resp *Response) error {
if attempts >= maxAttempts {
break
}

err = wrapErrWithUpstream(err, c.Addr)
Comment thread
mdenushev marked this conversation as resolved.
Outdated

if c.RetryIfErr != nil {
resetTimeout, retry = c.RetryIfErr(req, attempts, err)
Comment thread
mdenushev marked this conversation as resolved.
Outdated
} else {
Expand Down Expand Up @@ -1530,6 +1533,37 @@ func (e *timeoutError) Timeout() bool {
return true
}

// ErrWithUpstream wraps errors with upstream information where upstream info exists.
//
// Should use errors.As to get upstream information from error:
//
// hc := fasthttp.HostClient{Addr: "foo.com,bar.com"}
// err := hc.Do(req, res)
//
// var upstreamErr *fasthttp.ErrWithUpstream
// if errors.As(err, &upstreamErr) {
// upstream = upstreamErr.Upstream // 34.206.39.153:80
Comment thread
erikdubbelboer marked this conversation as resolved.
// }
type ErrWithUpstream struct {
wrapErr error
Upstream string
Comment thread
mdenushev marked this conversation as resolved.
}

func (e *ErrWithUpstream) Error() string {
return fmt.Sprintf("error on upstream %s: %s", e.Upstream, e.wrapErr.Error())
}

func (e *ErrWithUpstream) Unwrap() error {
return e.wrapErr
}

func wrapErrWithUpstream(err error, upstream string) *ErrWithUpstream {
return &ErrWithUpstream{
wrapErr: err,
Upstream: upstream,
}
Comment thread
mdenushev marked this conversation as resolved.
Outdated
}

// ErrTimeout is returned from timed out calls.
var ErrTimeout = &timeoutError{}

Expand Down
14 changes: 7 additions & 7 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ func TestHostClientNegativeTimeout(t *testing.T) {
if err := c.DoTimeout(req, nil, -time.Second); err != ErrTimeout {
t.Fatalf("expected ErrTimeout error got: %+v", err)
}
if err := c.DoDeadline(req, nil, time.Now().Add(-time.Second)); err != ErrTimeout {
if err := c.DoDeadline(req, nil, time.Now().Add(-time.Second)); !errors.Is(err, ErrTimeout) {
t.Fatalf("expected ErrTimeout error got: %+v", err)
}
ln.Close()
Expand Down Expand Up @@ -184,7 +184,7 @@ func TestDoDeadlineRetry(t *testing.T) {
req := AcquireRequest()
req.Header.SetMethod(MethodGet)
req.SetRequestURI("http://example.com")
if err := c.DoDeadline(req, nil, time.Now().Add(time.Millisecond*200)); err != ErrTimeout {
if err := c.DoDeadline(req, nil, time.Now().Add(time.Millisecond*200)); !errors.Is(err, ErrTimeout) {
t.Fatalf("expected ErrTimeout error got: %+v", err)
}
ln.Close()
Expand Down Expand Up @@ -1715,7 +1715,7 @@ func TestClientFollowRedirects(t *testing.T) {
if err == nil {
t.Errorf("expecting error")
}
if err != ErrTimeout {
if !errors.Is(err, ErrTimeout) {
t.Errorf("unexpected error: %v. Expecting %v", err, ErrTimeout)
}

Expand Down Expand Up @@ -1908,7 +1908,7 @@ func testClientDoTimeoutError(t *testing.T, c *Client, n int) {
if err == nil {
t.Errorf("expecting error")
}
if err != ErrTimeout {
if !errors.Is(err, ErrTimeout) {
t.Errorf("unexpected error: %v. Expecting %v", err, ErrTimeout)
}
}
Expand All @@ -1921,7 +1921,7 @@ func testClientGetTimeoutError(t *testing.T, c *Client, n int) {
if err == nil {
t.Errorf("expecting error")
}
if err != ErrTimeout {
if !errors.Is(err, ErrTimeout) {
t.Errorf("unexpected error: %v. Expecting %v", err, ErrTimeout)
}
if statusCode != 0 {
Expand All @@ -1940,7 +1940,7 @@ func testClientRequestSetTimeoutError(t *testing.T, c *Client, n int) {
if err == nil {
t.Errorf("expecting error")
}
if err != ErrTimeout {
if !errors.Is(err, ErrTimeout) {
t.Errorf("unexpected error: %v. Expecting %v", err, ErrTimeout)
}
}
Expand Down Expand Up @@ -3050,7 +3050,7 @@ func TestHostClientMaxConnWaitTimeoutWithEarlierDeadline(t *testing.T) {
resp := AcquireResponse()

if err := c.DoDeadline(req, resp, time.Now().Add(timeout)); err != nil {
if err != ErrTimeout {
if !errors.Is(err, ErrTimeout) {
t.Errorf("unexpected error: %v. Expecting %v", err, ErrTimeout)
}
errTimeoutCount.Add(1)
Expand Down