The app query client (src/queryClient.ts) sets no retry option, so React Query's default applies — 3 retries with exponential backoff for every error, including 4xx. Expected client errors then retry pointlessly: e.g. the courseware outline's expected 403 (denied/logged-out learner) retries 3× (~7s) before it finally settles, and any 4xx slow-fails behind the backoff.
Adopt a smart retry that fails fast on 4xx and only retries server/network errors — the same policy landed in openedx/frontend-app-learner-dashboard#801. Use the existing getResponseStatus helper (src/data/http-error.ts) for consistency with the onError logging.
Proposed change (drafted by Claude 🤖)
export const createQueryClient = (store: Store) => new QueryClient({
queryCache: createAppQueryCache(store),
defaultOptions: {
queries: {
retry: (failureCount, error) => {
const status = getResponseStatus(error);
if (status !== undefined && status >= 400 && status < 500) { return false; }
return failureCount < 3;
},
},
},
});
Test: a 4xx query calls the fn once (no retry); a 5xx/network query retries up to 3×.
Part of #1946.
The app query client (
src/queryClient.ts) sets noretryoption, so React Query's default applies — 3 retries with exponential backoff for every error, including 4xx. Expected client errors then retry pointlessly: e.g. the courseware outline's expected 403 (denied/logged-out learner) retries 3× (~7s) before it finally settles, and any 4xx slow-fails behind the backoff.Adopt a smart retry that fails fast on 4xx and only retries server/network errors — the same policy landed in openedx/frontend-app-learner-dashboard#801. Use the existing
getResponseStatushelper (src/data/http-error.ts) for consistency with theonErrorlogging.Proposed change (drafted by Claude 🤖)
Test: a 4xx query calls the fn once (no retry); a 5xx/network query retries up to 3×.
Part of #1946.