From fffa283cd33f0fe43b550c6072ae6ad804f7d7f2 Mon Sep 17 00:00:00 2001 From: Manabu Niseki Date: Wed, 25 Feb 2026 14:14:59 +0900 Subject: [PATCH] fix: use time.After instead of time.Sleep --- api/client.go | 6 +++++- api/client_test.go | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/api/client.go b/api/client.go index 163d88a..2bb34c0 100644 --- a/api/client.go +++ b/api/client.go @@ -49,7 +49,11 @@ func (t *RetryTransport) RoundTrip(req *http.Request) (*http.Response, error) { "X-Rate-Limit-Scope", limitScope, "X-Rate-Limit-Window", limitWindow, ) - time.Sleep(time.Duration(retryAfterInt) * time.Second) + select { + case <-time.After(time.Duration(retryAfterInt) * time.Second): + case <-req.Context().Done(): + return nil, req.Context().Err() + } } } res, err = t.Transport.RoundTrip(req) diff --git a/api/client_test.go b/api/client_test.go index ad8089c..4ec34b5 100644 --- a/api/client_test.go +++ b/api/client_test.go @@ -1,11 +1,13 @@ package api import ( + "context" "encoding/json" "fmt" "net/http" "net/url" "testing" + "time" "github.com/h2non/gock" "github.com/stretchr/testify/assert" @@ -162,3 +164,21 @@ func TestNetworkError(t *testing.T) { assert.Equal(t, gock.IsDone(), true) } + +func TestRetryContextTimeout(t *testing.T) { + defer gock.Off() + + // Return 429 with a long reset-after to trigger the rate-limit wait + gock.New("http://testserver/"). + Get("/bar"). + Reply(http.StatusTooManyRequests). + SetHeaders(map[string]string{"X-Rate-Limit-Reset-After": "5"}). + JSON(map[string]string{"foo": "bar"}) + + ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) + defer cancel() + + c := newTestClient() + _, err := c.NewRequest().SetContext(ctx).Get("/bar") + assert.ErrorIs(t, err, context.DeadlineExceeded) +}