From c25e162841ef5b88d438a98b0dbb88b90032d1cf Mon Sep 17 00:00:00 2001 From: chiyi Date: Mon, 6 Jul 2026 15:43:31 +0800 Subject: [PATCH] =?UTF-8?q?grok=20=E5=88=A4=E6=AD=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/internal/service/tokens.go | 16 +++++++++------- backend/internal/service/v1.go | 5 ++++- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/backend/internal/service/tokens.go b/backend/internal/service/tokens.go index b602ffb..c34ecb2 100644 --- a/backend/internal/service/tokens.go +++ b/backend/internal/service/tokens.go @@ -968,10 +968,13 @@ func (s *TokenService) RefreshGrokLiveness(ctx context.Context) { } sub, serr := s.grok.FetchSubscription(ctx, it.Value) if serr != nil { - if errors.Is(serr, grok.ErrAuth) { - _, _ = s.tokens.Update(ctx, "grok", it.ID, map[string]any{"status": "disabled", "dead": true}) - } - continue // transient upstream error → leave as-is, retry next tick + // Any probe error — including 401/403 (ErrAuth) — is treated as + // transient: leave the account as-is and retry next tick. A grok sso + // can momentarily 401 (upstream blip / proxy hiccup / anti-bot) while + // still being fully valid, so a single auth failure must NOT kill a + // live account. Genuine membership loss is still caught below via an + // INACTIVE/empty subscription (!sub.Member). + continue } if sub == nil || !sub.Member { // no ACTIVE subscription (INACTIVE / empty) → membership lapsed → dead. @@ -980,9 +983,8 @@ func (s *TokenService) RefreshGrokLiveness(ctx context.Context) { } data, derr := s.grok.FetchCreditsBalance(ctx, it.Value) if derr != nil { - if errors.Is(derr, grok.ErrAuth) { - _, _ = s.tokens.Update(ctx, "grok", it.ID, map[string]any{"status": "disabled", "dead": true}) - } + // Same policy as the subscription probe: a credits-balance 401/403 is + // transient, never a reason to kill a live account. Skip and retry. continue } meta := cloneJSONMap(it.Meta) diff --git a/backend/internal/service/v1.go b/backend/internal/service/v1.go index 8bfba0a..db4ef4b 100644 --- a/backend/internal/service/v1.go +++ b/backend/internal/service/v1.go @@ -3085,7 +3085,10 @@ func (s *V1Service) markTokenFailure(ctx context.Context, pool string, token mod // the cookie. chatgpt/runway/leonardo auth means the stored credential is // dead — a raw JWT (chatgpt/runway) or a cookie whose session no longer // authenticates (leonardo) — there's nothing left to refresh from. - if pool == "chatgpt" || pool == "runway" || pool == "leonardo" || pool == "krea" || pool == "imagine" || pool == "grok" { + // grok is intentionally excluded: a grok sso can momentarily 401 while + // still valid (upstream blip / proxy / anti-bot), so an auth failure just + // fails over for this request without permanently killing the account. + if pool == "chatgpt" || pool == "runway" || pool == "leonardo" || pool == "krea" || pool == "imagine" { patch["status"] = "disabled" patch["dead"] = true }