From 3fa5b8bca5d32c80a28212ad228d2a0d2c6bf667 Mon Sep 17 00:00:00 2001 From: erio Date: Tue, 14 Apr 2026 20:13:59 +0800 Subject: [PATCH] fix: flaky WebSocket test, usage request queue, and test improvements - Fix flaky WebSocket passthrough test: allow StatusNormalClosure after client close instead of requiring NoError (race condition fix) - Fix ratelimit 401 test: use PlatformOpenAI instead of PlatformGemini for OAuth token cache invalidation scenario (more accurate) - Add usageLoadQueue: Anthropic OAuth/setup-token accounts sharing the same proxy exit are serialized with 1-2s jitter to prevent upstream 429 - AccountUsageCell: add module-level usage cache (5min TTL), unmounted safety guard, and integrate enqueueUsageRequest for throttled fetching --- ...penai_ws_forwarder_ingress_session_test.go | 7 +- .../service/ratelimit_service_401_test.go | 4 +- .../components/account/AccountUsageCell.vue | 46 +++- .../utils/__tests__/usageLoadQueue.spec.ts | 205 ++++++++++++++++++ frontend/src/utils/usageLoadQueue.ts | 93 ++++++++ 5 files changed, 344 insertions(+), 11 deletions(-) create mode 100644 frontend/src/utils/__tests__/usageLoadQueue.spec.ts create mode 100644 frontend/src/utils/usageLoadQueue.ts diff --git a/backend/internal/service/openai_ws_forwarder_ingress_session_test.go b/backend/internal/service/openai_ws_forwarder_ingress_session_test.go index c527f2eb..6bf9a9ff 100644 --- a/backend/internal/service/openai_ws_forwarder_ingress_session_test.go +++ b/backend/internal/service/openai_ws_forwarder_ingress_session_test.go @@ -413,7 +413,12 @@ func TestOpenAIGatewayService_ProxyResponsesWebSocketFromClient_PassthroughModeR select { case serverErr := <-serverErrCh: - require.NoError(t, serverErr) + // After normal client close, the server goroutine may receive the close frame + // as an error — this is expected behavior, not a test failure. + if serverErr != nil { + require.Contains(t, serverErr.Error(), "StatusNormalClosure", + "server error should only be a normal close frame, got: %v", serverErr) + } case <-time.After(5 * time.Second): t.Fatal("等待 passthrough websocket 结束超时") } diff --git a/backend/internal/service/ratelimit_service_401_test.go b/backend/internal/service/ratelimit_service_401_test.go index 67b22e52..9e5e2b0e 100644 --- a/backend/internal/service/ratelimit_service_401_test.go +++ b/backend/internal/service/ratelimit_service_401_test.go @@ -102,6 +102,8 @@ func TestRateLimitService_HandleUpstreamError_OAuth401SetsTempUnschedulable(t *t }) } +// TestRateLimitService_HandleUpstreamError_OAuth401InvalidatorError +// OpenAI OAuth 401 缓存失效出错时仍走 temp_unschedulable func TestRateLimitService_HandleUpstreamError_OAuth401InvalidatorError(t *testing.T) { repo := &rateLimitAccountRepoStub{} invalidator := &tokenCacheInvalidatorRecorder{err: errors.New("boom")} @@ -109,7 +111,7 @@ func TestRateLimitService_HandleUpstreamError_OAuth401InvalidatorError(t *testin service.SetTokenCacheInvalidator(invalidator) account := &Account{ ID: 101, - Platform: PlatformGemini, + Platform: PlatformOpenAI, Type: AccountTypeOAuth, } diff --git a/frontend/src/components/account/AccountUsageCell.vue b/frontend/src/components/account/AccountUsageCell.vue index 2e4eea0c..1c023fb3 100644 --- a/frontend/src/components/account/AccountUsageCell.vue +++ b/frontend/src/components/account/AccountUsageCell.vue @@ -439,15 +439,20 @@