Повторные попытки выполнения запросов в TanStack Query являются встроенным механизмом устойчивости к сетевым сбоям и временным ошибкам серверной стороны. Логика retry применяется как для query, так и для mutation, но настраивается отдельно и может быть переопределена на разных уровнях: глобально через QueryClient, локально через конкретный запрос или мутацию, а также динамически через функцию, принимающую контекст ошибки.
В стандартной конфигурации TanStack Query автоматически повторяет неуспешные запросы несколько раз. Поведение определяется следующими параметрами:
retry — количество попыток или функция-решательretryDelay — задержка между попыткамиПо умолчанию библиотека использует ограниченное число повторов (обычно 3) для ошибок сети или временных сбоев.
Повтор не выполняется, если:
retry установлен в falseГлобальная настройка определяет поведение всех запросов по умолчанию:
import { QueryClient } from '@tanstack/react-query'
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: 3,
retryDelay: attemptIndex => Math.min(1000 * 2 ** attemptIndex, 30000),
},
},
})
Здесь используется экспоненциальная задержка, при которой интервал увеличивается с каждой попыткой. Такая стратегия снижает нагрузку на сервер при массовых сбоях и уменьшает вероятность повторного отказа.
Любой query может переопределить глобальные настройки:
useQuery({
queryKey: ['users'],
queryFn: fetchUsers,
retry: 1,
})
или полностью отключить повторы:
useQuery({
queryKey: ['auth'],
queryFn: fetchSession,
retry: false,
})
Отключение retry часто используется для:
Наиболее гибкий вариант — передача функции, принимающей количество попыток и ошибку:
useQuery({
queryKey: ['profile'],
queryFn: fetchProfile,
retry: (failureCount, error) => {
if (error.status === 404) return false
if (failureCount > 5) return false
return true
},
})
Функция позволяет реализовать условную логику:
Повторы для query и mutation имеют принципиальные различия.
Query:
Mutation:
useMutation({
mutationFn: createUser,
retry: 0,
})
Для mutation повтор может привести к:
Параметр retryDelay управляет интервалом между
попытками.
Статическая задержка:
retryDelay: 2000
Экспоненциальная стратегия:
retryDelay: attemptIndex =>
Math.min(1000 * 2 ** attemptIndex, 30000)
Добавление случайного jitter:
retryDelay: attemptIndex =>
Math.min(1000 * 2 ** attemptIndex, 30000) *
(0.5 + Math.random())
Jitter снижает вероятность «thundering herd problem», когда множество клиентов одновременно повторяют запросы после сбоя.
Часто требуется различать временные и постоянные ошибки:
useQuery({
queryKey: ['post', id],
queryFn: fetchPost,
retry: (failureCount, error) => {
if (error?.status >= 400 && error?.status < 500) {
return false
}
return failureCount < 3
},
})
Клиентские ошибки (4xx) обычно не имеют смысла для повторов, тогда как серверные (5xx) или сетевые сбои являются кандидатами на retry.
TanStack Query учитывает состояние онлайн/офлайн, но retry может комбинироваться с этим поведением.
При восстановлении соединения:
Настройка networkMode влияет на это поведение:
useQuery({
queryKey: ['dashboard'],
queryFn: fetchDashboard,
networkMode: 'online',
retry: 2,
})
Режимы позволяют контролировать, выполняются ли попытки при отсутствии сети или откладываются до восстановления соединения.
Повтор не выполняется, если запрос был отменён через AbortController:
const queryFn = async ({ signal }) => {
const res = await fetch('/api/data', { signal })
return res.json()
}
При отмене:
Это важно для предотвращения утечек ресурсов при быстрых переключениях UI.
Часто требуется разное поведение для development и production:
const isDev = process.env.NODE_ENV === 'development'
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: isDev ? 0 : 3,
},
},
})
В development повторные запросы могут скрывать реальные ошибки и замедлять отладку, поэтому их обычно отключают.
Поведение retry влияет на UX только при отсутствии актуальных данных в кеше. Если данные свежие:
Конфигурация:
useQuery({
queryKey: ['settings'],
queryFn: fetchSettings,
staleTime: 60000,
retry: 2,
})
При высокой staleTime вероятность запуска retry
снижается, так как библиотека предпочитает использовать кэш.
В системах с высоким трафиком чрезмерные retry могут усугубить нагрузку. Используются ограничения:
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: 1,
retryDelay: attempt =>
Math.min(2000 * attempt, 10000),
},
},
})
Retry-логика часто сопровождается мониторингом:
useQuery({
queryKey: ['analytics'],
queryFn: fetchAnalytics,
retry: (count, error) => {
console.log('retry attempt', count, error)
return count < 3
},
})
В продакшене подобная логика обычно заменяется интеграцией с системами наблюдаемости, где фиксируются:
Продвинутые сценарии включают:
retry: (failureCount, error) => {
if (error?.response?.headers?.['x-no-retry'] === 'true') {
return false
}
return failureCount < 3
}
Такая модель позволяет серверу участвовать в управлении клиентским поведением.
Логика повторов в TanStack Query представляет собой многоуровневую систему, где решение о повторе формируется на основе:
Эта гибкость позволяет адаптировать поведение запросов под любые сценарии — от высоконагруженных API до клиентских интерфейсов с критичными операциями.