diff --git a/caboose.go b/caboose.go index 4ec7af3..3c49530 100644 --- a/caboose.go +++ b/caboose.go @@ -104,25 +104,31 @@ var ErrSaturnTimeout error = errors.New("saturn backend timed out") type ErrSaturnTooManyRequests struct { Node string - RetryAfter time.Duration // TODO: DRY refactor after https://github.com/ipfs/go-libipfs/issues/188 + retryAfter time.Duration } -func (e ErrSaturnTooManyRequests) Error() string { - return fmt.Sprintf("saturn node %s returned Too Many Requests error, please retry after %s", e.Node, humanRetry(e.RetryAfter)) +func (e *ErrSaturnTooManyRequests) Error() string { + return fmt.Sprintf("saturn node %s returned Too Many Requests error, please retry after %s", e.Node, humanRetry(e.retryAfter)) +} + +func (e *ErrSaturnTooManyRequests) RetryAfter() time.Duration { + return e.retryAfter } type ErrCoolDown struct { Cid cid.Cid Path string - RetryAfter time.Duration // TODO: DRY refactor after https://github.com/ipfs/go-libipfs/issues/188 + retryAfter time.Duration } func (e *ErrCoolDown) Error() string { - return fmt.Sprintf("multiple saturn retrieval failures seen for CID %s/Path %s, please retry after %s", e.Cid, e.Path, humanRetry(e.RetryAfter)) + return fmt.Sprintf("multiple saturn retrieval failures seen for CID %s/Path %s, please retry after %s", e.Cid, e.Path, humanRetry(e.retryAfter)) +} + +func (e *ErrCoolDown) RetryAfter() time.Duration { + return e.retryAfter } -// TODO: move this to upstream error interface in https://github.com/ipfs/go-libipfs/issues/188 -// and refactor ErrCoolDown and ErrSaturnTooManyRequests to inherit from that instead func humanRetry(d time.Duration) string { return d.Truncate(time.Second).String() } diff --git a/failure_test.go b/failure_test.go index 601e948..7ce34c3 100644 --- a/failure_test.go +++ b/failure_test.go @@ -2,15 +2,16 @@ package caboose_test import ( "context" + "errors" "net/http" "net/http/httptest" "sync" "testing" "time" + "github.com/filecoin-saturn/caboose" "github.com/stretchr/testify/require" - "github.com/filecoin-saturn/caboose" "github.com/ipfs/go-cid" "github.com/multiformats/go-multicodec" ) @@ -30,8 +31,10 @@ func TestHttp429(t *testing.T) { _, err := ch.c.Get(ctx, testCid) require.Error(t, err) - ferr := err.(*caboose.ErrSaturnTooManyRequests) - require.EqualValues(t, expRetryAfter, ferr.RetryAfter) + var ferr *caboose.ErrSaturnTooManyRequests + ok := errors.As(err, &ferr) + require.True(t, ok) + require.EqualValues(t, expRetryAfter, ferr.RetryAfter()) } func TestCabooseTransientFailures(t *testing.T) { @@ -163,10 +166,12 @@ func (ch *CabooseHarness) runFetchesForRandCids(n int) { func (ch *CabooseHarness) fetchAndAssertCoolDownError(t *testing.T, ctx context.Context, cid cid.Cid) { _, err := ch.c.Get(ctx, cid) require.Error(t, err) - coolDownErr, ok := err.(*caboose.ErrCoolDown) + + var coolDownErr *caboose.ErrCoolDown + ok := errors.As(err, &coolDownErr) require.True(t, ok) require.EqualValues(t, cid, coolDownErr.Cid) - require.NotZero(t, coolDownErr.RetryAfter) + require.NotZero(t, coolDownErr.RetryAfter()) } func (ch *CabooseHarness) fetchAndAssertFailure(t *testing.T, ctx context.Context, testCid cid.Cid, contains string) { diff --git a/fetcher.go b/fetcher.go index fa743ea..f9f11a2 100644 --- a/fetcher.go +++ b/fetcher.go @@ -188,7 +188,7 @@ func (p *pool) fetchResource(ctx context.Context, from string, resource string, retryAfter = p.config.SaturnNodeCoolOff } - return fmt.Errorf("http error from strn: %d, err=%w", resp.StatusCode, ErrSaturnTooManyRequests{RetryAfter: retryAfter, Node: from}) + return fmt.Errorf("http error from strn: %d, err=%w", resp.StatusCode, &ErrSaturnTooManyRequests{retryAfter: retryAfter, Node: from}) } // empty body so it can be re-used. diff --git a/pool.go b/pool.go index 3fe2129..e59f4cb 100644 --- a/pool.go +++ b/pool.go @@ -286,7 +286,7 @@ func (p *pool) fetchBlockWith(ctx context.Context, c cid.Cid, with string) (blk expireAt := at.(time.Time) return nil, &ErrCoolDown{ Cid: c, - RetryAfter: time.Until(expireAt), + retryAfter: time.Until(expireAt), } } p.fetchKeyLk.RUnlock() @@ -426,7 +426,7 @@ func (p *pool) fetchResourceWith(ctx context.Context, path string, cb DataCallba expireAt := at.(time.Time) return &ErrCoolDown{ Path: path, - RetryAfter: time.Until(expireAt), + retryAfter: time.Until(expireAt), } } p.fetchKeyLk.RUnlock() @@ -517,14 +517,8 @@ func (p *pool) commonUpdate(node string, err error) (ferr error) { } } - var errTooManyRequests ErrSaturnTooManyRequests - if errors.As(err, &errTooManyRequests) { - - ferr = &ErrSaturnTooManyRequests{ - Node: errTooManyRequests.Node, - RetryAfter: errTooManyRequests.RetryAfter, - } - + if errors.Is(err, &ErrSaturnTooManyRequests{}) { + ferr = err if ok := p.isCoolOffLocked(node); ok { return }