From d3a479ed7659be70a3856bcb57b64e5c806d6a3e Mon Sep 17 00:00:00 2001 From: chiyi Date: Mon, 6 Jul 2026 15:52:09 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=AF=AF=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 | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/backend/internal/service/tokens.go b/backend/internal/service/tokens.go index c34ecb2..0c93b39 100644 --- a/backend/internal/service/tokens.go +++ b/backend/internal/service/tokens.go @@ -966,15 +966,27 @@ func (s *TokenService) RefreshGrokLiveness(ctx context.Context) { if it.Pool != "grok" || it.Dead || it.Status == "disabled" || strings.TrimSpace(it.Value) == "" { continue } - sub, serr := s.grok.FetchSubscription(ctx, it.Value) + // A grok sso can momentarily 401 (upstream blip / proxy hiccup / anti-bot) + // while still being fully valid, so a single auth failure must never kill a + // live account. Retry the subscription probe up to 3 times on 401/403; only + // if all 3 attempts still return ErrAuth do we treat the session as dead. + var sub *grok.Subscription + var serr error + for attempt := 1; attempt <= 3; attempt++ { + sub, serr = s.grok.FetchSubscription(ctx, it.Value) + if serr == nil || !errors.Is(serr, grok.ErrAuth) { + break + } + if attempt < 3 { + time.Sleep(2 * time.Second) + } + } if serr != nil { - // 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 errors.Is(serr, grok.ErrAuth) { + // 3 consecutive 401/403 → the sso session is genuinely dead. + _, _ = s.tokens.Update(ctx, "grok", it.ID, map[string]any{"status": "disabled", "dead": true}) + } + continue // other transient upstream error → leave as-is, retry next tick } if sub == nil || !sub.Member { // no ACTIVE subscription (INACTIVE / empty) → membership lapsed → dead.