mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-14 12:02:27 +08:00
fix(opencode): cap Retry-After hint at 24h for usage refresh backoff
This commit is contained in:
@@ -1000,8 +1000,17 @@ func decodeOpenCodeGoUsageSnapshot(extra map[string]any) *OpenCodeGoUsageSnapsho
|
||||
|
||||
// nextOpenCodeGoUsageDelay computes the not-before delay for the next refresh:
|
||||
// interval * 2^min(failureCount-1, 6) capped at 24h, ±10% jitter capped at 5min,
|
||||
// never below a Retry-After hint or one minute.
|
||||
// never below a Retry-After hint or one minute. The hint is honored over the
|
||||
// local backoff but clamped to the same 24h ceiling: it arrives over a network
|
||||
// path we do not control (upstream CDN, account proxy), and an unbounded value
|
||||
// would freeze a group's auto refresh indefinitely.
|
||||
func nextOpenCodeGoUsageDelay(intervalMinutes, failureCount int, retryAfterDuration time.Duration) time.Duration {
|
||||
if retryAfterDuration < 0 {
|
||||
retryAfterDuration = 0
|
||||
}
|
||||
if retryAfterDuration > opencodeGoUsageMaxDelay {
|
||||
retryAfterDuration = opencodeGoUsageMaxDelay
|
||||
}
|
||||
minimumDelay := retryAfterDuration
|
||||
base := time.Duration(intervalMinutes) * time.Minute
|
||||
if base < opencodeGoUsageMinIntervalMinutes*time.Minute {
|
||||
|
||||
@@ -403,11 +403,39 @@ func TestNextOpenCodeGoUsageDelayBackoff(t *testing.T) {
|
||||
delay = nextOpenCodeGoUsageDelay(15, 0, 2*time.Hour)
|
||||
require.GreaterOrEqual(t, delay, 2*time.Hour)
|
||||
|
||||
// a hint beyond the 24h ceiling is clamped, never adopted verbatim
|
||||
delay = nextOpenCodeGoUsageDelay(15, 0, 48*time.Hour)
|
||||
require.GreaterOrEqual(t, delay, 23*time.Hour+55*time.Minute)
|
||||
require.LessOrEqual(t, delay, 24*time.Hour+5*time.Minute)
|
||||
|
||||
// floor of one minute
|
||||
delay = nextOpenCodeGoUsageDelay(5, 0, 0)
|
||||
require.GreaterOrEqual(t, delay, time.Minute)
|
||||
}
|
||||
|
||||
func TestOpenCodeGoUsageRefreshClampsHugeRetryAfter(t *testing.T) {
|
||||
now := time.Now().UTC()
|
||||
account := openCodeGoUsageAccount(7)
|
||||
repo := &openCodeGoUsageTestRepo{accounts: map[int64]*Account{7: account}}
|
||||
stub := &openCodeGoUsageHTTPStub{
|
||||
status: http.StatusTooManyRequests,
|
||||
header: http.Header{"Retry-After": []string{"99999999"}},
|
||||
}
|
||||
svc := newOpenCodeGoUsageTestService(t, repo, stub, &upstreamBillingProbeSettingRepo{})
|
||||
svc.now = func() time.Time { return now }
|
||||
|
||||
state, err := svc.Refresh(context.Background(), 7)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, OpenCodeGoUsageStatusFailed, state.Snapshot.Status)
|
||||
require.Equal(t, http.StatusTooManyRequests, state.Snapshot.HTTPStatus)
|
||||
require.Equal(t, "http_error", state.Snapshot.LastError)
|
||||
|
||||
maxExpected := now.Add(24*time.Hour + 5*time.Minute)
|
||||
minExpected := now.Add(23*time.Hour + 55*time.Minute)
|
||||
require.True(t, state.Snapshot.NextRefreshAt.Before(maxExpected.Add(time.Second)))
|
||||
require.True(t, state.Snapshot.NextRefreshAt.After(minExpected.Add(-time.Second)))
|
||||
}
|
||||
|
||||
func TestOpenCodeGoUsageManualRefreshThrottle(t *testing.T) {
|
||||
now := time.Now().UTC()
|
||||
account := openCodeGoUsageAccount(7)
|
||||
|
||||
Reference in New Issue
Block a user