From d65231f2119edb64a61d6044bd758181a068bb35 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Mon, 6 Mar 2023 04:44:34 +0100 Subject: [PATCH 1/4] feat: pass Retry-After to end user Based on https://github.com/ipfs/go-libipfs/pull/194 --- blockstore.go | 14 +++++++++++++- go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/blockstore.go b/blockstore.go index 7b343e8..f2f4371 100644 --- a/blockstore.go +++ b/blockstore.go @@ -68,8 +68,10 @@ func (e *exchangeBsWrapper) Close() error { } // gatewayError translates underlying blockstore error into one that gateway code will return as HTTP 502 or 504 +// it also makes sure Retry-After hint from remote blockstore will be passed to HTTP client, if present. func gatewayError(err error) error { - if errors.Is(err, gateway.ErrGatewayTimeout) || errors.Is(err, gateway.ErrBadGateway) { + if errors.Is(err, &gateway.ErrorResponse{}) || + errors.Is(err, &gateway.ErrorRetryAfter{}) { // already correct error return err } @@ -82,6 +84,16 @@ func gatewayError(err error) error { return fmt.Errorf("%w: %s", gateway.ErrGatewayTimeout, err.Error()) } + // Saturn errors with RetryAfter hint need to be converted to Gateway ones + var saturnTooManyRequests *caboose.ErrSaturnTooManyRequests + if errors.As(err, &saturnTooManyRequests) { + return gateway.NewErrorRetryAfter(saturnTooManyRequests, saturnTooManyRequests.RetryAfter) + } + var saturnCidCoolDown *caboose.ErrCidCoolDown + if errors.As(err, &saturnCidCoolDown) { + return gateway.NewErrorRetryAfter(saturnCidCoolDown, saturnCidCoolDown.RetryAfter) + } + // everything else returns 502 Bad Gateway return fmt.Errorf("%w: %s", gateway.ErrBadGateway, err.Error()) } diff --git a/go.mod b/go.mod index 83a1725..3831758 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/ipfs/go-ipfs-exchange-interface v0.2.0 github.com/ipfs/go-ipld-format v0.4.0 github.com/ipfs/go-ipns v0.3.0 - github.com/ipfs/go-libipfs v0.6.1-0.20230224152609-00e024995173 + github.com/ipfs/go-libipfs v0.6.1-0.20230306034211-49716dcef2e2 github.com/ipfs/go-log/v2 v2.5.1 github.com/ipfs/go-merkledag v0.9.0 github.com/ipfs/go-namesys v0.7.0 diff --git a/go.sum b/go.sum index 604fe29..994ec06 100644 --- a/go.sum +++ b/go.sum @@ -370,8 +370,8 @@ github.com/ipfs/go-ipld-legacy v0.1.1 h1:BvD8PEuqwBHLTKqlGFTHSwrwFOMkVESEvwIYwR2 github.com/ipfs/go-ipld-legacy v0.1.1/go.mod h1:8AyKFCjgRPsQFf15ZQgDB8Din4DML/fOmKZkkFkrIEg= github.com/ipfs/go-ipns v0.3.0 h1:ai791nTgVo+zTuq2bLvEGmWP1M0A6kGTXUsgv/Yq67A= github.com/ipfs/go-ipns v0.3.0/go.mod h1:3cLT2rbvgPZGkHJoPO1YMJeh6LtkxopCkKFcio/wE24= -github.com/ipfs/go-libipfs v0.6.1-0.20230224152609-00e024995173 h1:GO24W9RndedkB5jSuPbxPsF4wy0ZpqrXYG+Lf0RrdKY= -github.com/ipfs/go-libipfs v0.6.1-0.20230224152609-00e024995173/go.mod h1:3OoEQs95UkqFEf65SbRDpiMwuzI+C/jTsYQaHfBbJXI= +github.com/ipfs/go-libipfs v0.6.1-0.20230306034211-49716dcef2e2 h1:/owb2iBAdSX+b/0MtM2vMD6QVbaH9ricuAkOl1C94VE= +github.com/ipfs/go-libipfs v0.6.1-0.20230306034211-49716dcef2e2/go.mod h1:FmhKgxMOQA572TK5DA3MZ5GL44ZqsMHIrkgK4gLn4A8= github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk= github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A= From d3fec037a266f41844fefb25934271cc1427aac2 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Mon, 6 Mar 2023 09:51:08 +0100 Subject: [PATCH 2/4] chore: update go-libipfs --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 3831758..b481fac 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/ipfs/go-ipfs-exchange-interface v0.2.0 github.com/ipfs/go-ipld-format v0.4.0 github.com/ipfs/go-ipns v0.3.0 - github.com/ipfs/go-libipfs v0.6.1-0.20230306034211-49716dcef2e2 + github.com/ipfs/go-libipfs v0.6.1-0.20230306084414-15f2131fe190 github.com/ipfs/go-log/v2 v2.5.1 github.com/ipfs/go-merkledag v0.9.0 github.com/ipfs/go-namesys v0.7.0 diff --git a/go.sum b/go.sum index 994ec06..12fd780 100644 --- a/go.sum +++ b/go.sum @@ -370,8 +370,8 @@ github.com/ipfs/go-ipld-legacy v0.1.1 h1:BvD8PEuqwBHLTKqlGFTHSwrwFOMkVESEvwIYwR2 github.com/ipfs/go-ipld-legacy v0.1.1/go.mod h1:8AyKFCjgRPsQFf15ZQgDB8Din4DML/fOmKZkkFkrIEg= github.com/ipfs/go-ipns v0.3.0 h1:ai791nTgVo+zTuq2bLvEGmWP1M0A6kGTXUsgv/Yq67A= github.com/ipfs/go-ipns v0.3.0/go.mod h1:3cLT2rbvgPZGkHJoPO1YMJeh6LtkxopCkKFcio/wE24= -github.com/ipfs/go-libipfs v0.6.1-0.20230306034211-49716dcef2e2 h1:/owb2iBAdSX+b/0MtM2vMD6QVbaH9ricuAkOl1C94VE= -github.com/ipfs/go-libipfs v0.6.1-0.20230306034211-49716dcef2e2/go.mod h1:FmhKgxMOQA572TK5DA3MZ5GL44ZqsMHIrkgK4gLn4A8= +github.com/ipfs/go-libipfs v0.6.1-0.20230306084414-15f2131fe190 h1:uLCIMrKU1/SlZVDrTNfX3p6y4hv+cSZn51xiKU3glV8= +github.com/ipfs/go-libipfs v0.6.1-0.20230306084414-15f2131fe190/go.mod h1:FmhKgxMOQA572TK5DA3MZ5GL44ZqsMHIrkgK4gLn4A8= github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk= github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A= From 476ffb6452e1f69c0883d6d35934302321be2be7 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Wed, 8 Mar 2023 10:28:20 +0100 Subject: [PATCH 3/4] feat: update caboose, support .RetryAfter errors --- blockstore.go | 14 ++++++-------- go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/blockstore.go b/blockstore.go index f2f4371..dbce766 100644 --- a/blockstore.go +++ b/blockstore.go @@ -84,14 +84,12 @@ func gatewayError(err error) error { return fmt.Errorf("%w: %s", gateway.ErrGatewayTimeout, err.Error()) } - // Saturn errors with RetryAfter hint need to be converted to Gateway ones - var saturnTooManyRequests *caboose.ErrSaturnTooManyRequests - if errors.As(err, &saturnTooManyRequests) { - return gateway.NewErrorRetryAfter(saturnTooManyRequests, saturnTooManyRequests.RetryAfter) - } - var saturnCidCoolDown *caboose.ErrCidCoolDown - if errors.As(err, &saturnCidCoolDown) { - return gateway.NewErrorRetryAfter(saturnCidCoolDown, saturnCidCoolDown.RetryAfter) + // (Saturn) errors that support the RetryAfter interface need to be converted + // to the correct gateway error, such that the HTTP header is set. + for v := err; v != nil; v = errors.Unwrap(v) { + if r, ok := v.(interface{ RetryAfter() time.Duration }); ok { + return gateway.NewErrorRetryAfter(err, r.RetryAfter()) + } } // everything else returns 502 Bad Gateway diff --git a/go.mod b/go.mod index b481fac..ff0251b 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/ipfs/bifrost-gateway go 1.19 require ( - github.com/filecoin-saturn/caboose v0.0.0-20230302152536-a518e617b034 + github.com/filecoin-saturn/caboose v0.0.0-20230308085731-e621c985ff5b github.com/gogo/protobuf v1.3.2 github.com/hashicorp/golang-lru/v2 v2.0.1 github.com/ipfs/go-blockservice v0.5.0 diff --git a/go.sum b/go.sum index 12fd780..5b94f56 100644 --- a/go.sum +++ b/go.sum @@ -128,8 +128,8 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/filecoin-saturn/caboose v0.0.0-20230302152536-a518e617b034 h1:2FW0FRhQdeXfrZc9O5gfHVo1nImi7IYmvyoghqiDCwk= -github.com/filecoin-saturn/caboose v0.0.0-20230302152536-a518e617b034/go.mod h1:8r461tw36fg57kfCPGILFE0bWRodig93n0F1S90VIVg= +github.com/filecoin-saturn/caboose v0.0.0-20230308085731-e621c985ff5b h1:uCD6KPv/Vhm6Y9tfwpIpVJ64VV/ZJd4eFwFMlaI9/OI= +github.com/filecoin-saturn/caboose v0.0.0-20230308085731-e621c985ff5b/go.mod h1:8r461tw36fg57kfCPGILFE0bWRodig93n0F1S90VIVg= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= From e41abe2f39914db3b7f2cd4cfe27ca6ee842d4f3 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Wed, 8 Mar 2023 10:55:13 +0100 Subject: [PATCH 4/4] feat: add test for error retry after --- blockstore_test.go | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 blockstore_test.go diff --git a/blockstore_test.go b/blockstore_test.go new file mode 100644 index 0000000..7376ffa --- /dev/null +++ b/blockstore_test.go @@ -0,0 +1,44 @@ +package main + +import ( + "errors" + "fmt" + "testing" + "time" + + "github.com/ipfs/go-libipfs/gateway" + "github.com/stretchr/testify/assert" +) + +type testErr struct { + message string + retryAfter time.Duration +} + +func (e *testErr) Error() string { + return e.message +} + +func (e *testErr) RetryAfter() time.Duration { + return e.retryAfter +} + +func TestGatewayErrorRetryAfter(t *testing.T) { + originalErr := &testErr{message: "test", retryAfter: time.Minute} + var ( + convertedErr error + gatewayErr *gateway.ErrorRetryAfter + ) + + // Test unwrapped + convertedErr = gatewayError(originalErr) + ok := errors.As(convertedErr, &gatewayErr) + assert.True(t, ok) + assert.EqualValues(t, originalErr.retryAfter, gatewayErr.RetryAfter) + + // Test wrapped. + convertedErr = gatewayError(fmt.Errorf("wrapped error: %w", originalErr)) + ok = errors.As(convertedErr, &gatewayErr) + assert.True(t, ok) + assert.EqualValues(t, originalErr.retryAfter, gatewayErr.RetryAfter) +}