fix(utils): honor Retry-After for 429 retries

This commit is contained in:
Alix-007
2026-03-30 13:04:51 +08:00
parent 93f4c4a843
commit cd3f6600ca
2 changed files with 103 additions and 1 deletions
+75
View File
@@ -80,6 +80,81 @@ func TestDoRequestWithRetry(t *testing.T) {
}
}
func TestDoRequestWithRetry_RetryAfter429Honored(t *testing.T) {
retryDelayUnit = 10 * time.Millisecond
t.Cleanup(func() { retryDelayUnit = time.Second })
attempts := 0
var firstAttemptAt time.Time
var secondAttemptAt time.Time
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
attempts++
if attempts == 1 {
firstAttemptAt = time.Now()
w.Header().Set("Retry-After", "1")
w.WriteHeader(http.StatusTooManyRequests)
return
}
if attempts == 2 {
secondAttemptAt = time.Now()
}
w.WriteHeader(http.StatusOK)
}))
defer server.Close()
client := &http.Client{Timeout: 5 * time.Second}
req, err := http.NewRequest(http.MethodGet, server.URL, nil)
require.NoError(t, err)
resp, err := DoRequestWithRetry(client, req)
require.NoError(t, err)
require.NotNil(t, resp)
assert.Equal(t, http.StatusOK, resp.StatusCode)
resp.Body.Close()
require.Equal(t, 2, attempts)
assert.GreaterOrEqual(t, secondAttemptAt.Sub(firstAttemptAt), 900*time.Millisecond)
}
func TestDoRequestWithRetry_RetryAfter429InvalidFallsBack(t *testing.T) {
retryDelayUnit = 50 * time.Millisecond
t.Cleanup(func() { retryDelayUnit = time.Second })
attempts := 0
var firstAttemptAt time.Time
var secondAttemptAt time.Time
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
attempts++
if attempts == 1 {
firstAttemptAt = time.Now()
w.Header().Set("Retry-After", "invalid")
w.WriteHeader(http.StatusTooManyRequests)
return
}
if attempts == 2 {
secondAttemptAt = time.Now()
}
w.WriteHeader(http.StatusOK)
}))
defer server.Close()
client := &http.Client{Timeout: 5 * time.Second}
req, err := http.NewRequest(http.MethodGet, server.URL, nil)
require.NoError(t, err)
resp, err := DoRequestWithRetry(client, req)
require.NoError(t, err)
require.NotNil(t, resp)
assert.Equal(t, http.StatusOK, resp.StatusCode)
resp.Body.Close()
require.Equal(t, 2, attempts)
assert.GreaterOrEqual(t, secondAttemptAt.Sub(firstAttemptAt), 45*time.Millisecond)
assert.Less(t, secondAttemptAt.Sub(firstAttemptAt), 500*time.Millisecond)
}
func TestDoRequestWithRetry_ContextCancel(t *testing.T) {
// Use a long retry delay so cancellation always hits during sleepWithCtx.
retryDelayUnit = 10 * time.Second