From 6444dc0ebd6114339c1631fa60013baeba6e65ac Mon Sep 17 00:00:00 2001 From: Light1YT Date: Sat, 13 Jun 2026 16:47:58 +0500 Subject: [PATCH] =?UTF-8?q?fix(tradein-frontend):=20=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D0=B0=D0=BD=D0=BE=D0=B2=D0=B8=D1=82=D1=8C=20retry-storm=20?= =?UTF-8?q?=D0=BD=D0=B0=20401=20=E2=80=94=20refetchOnMount:false=20+=20bac?= =?UTF-8?q?koff=20(#800)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit На стойком 401/протухшей сессии фронт повторял /me + /trade-in/quota в бесконечном цикле (184+ запросов): errored query + дефолтный refetchOnMount=true → каждый новый observer (useMe дёргают RouteGuard, Topbar, UserMenu, useBrand) ре-фетчил при mount = re-subscribe storm. Глобально выключаем refetchOnMount/onReconnect в QueryClient + экспоненциальный retryDelay (cap 30s); те же гарды на useQuota. retry-предикат 4xx→false уже был. Graceful session-screen (RouteGuard/NoAccessScreen) уже на месте. Closes #800 --- tradein-mvp/frontend/src/app/providers.tsx | 15 +++++++++++++-- tradein-mvp/frontend/src/lib/useQuota.ts | 8 ++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/tradein-mvp/frontend/src/app/providers.tsx b/tradein-mvp/frontend/src/app/providers.tsx index 38c3cbe9..47211624 100644 --- a/tradein-mvp/frontend/src/app/providers.tsx +++ b/tradein-mvp/frontend/src/app/providers.tsx @@ -11,13 +11,24 @@ export function Providers({ children }: { children: React.ReactNode }) { queries: { staleTime: 5 * 60_000, refetchOnWindowFocus: false, - // #770 finding #26: не ретраить 4xx (включая 429) — иначе на rate-limit - // дефолтные 3 ретрая превращаются в шторм. Ретраим только 5xx/сеть, ≤2 раза. + // #800: errored query + дефолтный refetchOnMount=true → каждый новый + // observer (Topbar/UserMenu/useBrand все дёргают useMe) ре-фетчит при + // mount → re-subscribe storm на стойком 401. Выключаем глобально: данные + // и так staleTime-кэшируются, а auth/quota не должны бить бэк на ремаунт. + refetchOnMount: false, + refetchOnReconnect: false, + // #770 finding #26 + #800: не ретраить 4xx (401/403/429) — иначе на + // rate-limit/протухшей сессии дефолтные 3 ретрая превращаются в шторм + // в собственный бэкенд. Ретраим только 5xx/сеть, ≤2 раза. retry: (failureCount, error) => { const status = (error as { status?: number } | null)?.status; if (typeof status === "number" && status >= 400 && status < 500) return false; return failureCount < 2; }, + // #800: экспоненциальный backoff на сетевых/5xx ретраях (1s, 2s, 4s… + // capped 30s) — никаких немедленных повторов, мягко к бэкенду. + retryDelay: (attemptIndex) => + Math.min(1000 * 2 ** attemptIndex, 30_000), }, mutations: { retry: false, diff --git a/tradein-mvp/frontend/src/lib/useQuota.ts b/tradein-mvp/frontend/src/lib/useQuota.ts index e5f60b7d..8545eec1 100644 --- a/tradein-mvp/frontend/src/lib/useQuota.ts +++ b/tradein-mvp/frontend/src/lib/useQuota.ts @@ -10,6 +10,11 @@ const BASE = "/api/v1/trade-in"; * GET /api/v1/trade-in/quota * Fetches the monthly evaluation quota status for the current session/account. * Fail-open: if the query errors, the UI must NOT block the user (treat as unlimited). + * + * #800: `retry:false` — на 401/протухшей сессии quota НЕ должна ре-стучаться в бэк. + * `refetchOnMount/Reconnect/WindowFocus:false` — иначе errored quota ре-фетчит на + * каждый ремаунт владельца → вклад в retry-storm. Освежается явным + * `invalidateQueries(["trade-in","quota"])` после успешной оценки (см. page.tsx). */ export function useQuota() { return useQuery({ @@ -17,5 +22,8 @@ export function useQuota() { queryFn: () => apiFetch(`${BASE}/quota`), staleTime: 30_000, retry: false, + refetchOnMount: false, + refetchOnReconnect: false, + refetchOnWindowFocus: false, }); } -- 2.45.3