Фоновые задачи с ретраями — без флота воркеров
Фоновые задачи падают: API таймаутят, базы блокируются, сеть моргает. Платформе ретраев нужны backoff на шаг, идемпотентные обработчики и история сбоев с поиском — а не цикл while в воркер-процессе. Пайплайны Inquir автоматически повторяют упавшие шаги, сохраняя завершённую работу в чекпоинтах.
Обновлено: 2026-06-28
Кратко
Суть ответа
Фоновые задачи с ретраями — без флота воркеров. Каждый шаг пайплайна повторяется при сбое независимо. Завершённые шаги остаются в чекпоинтах — перезапускается только упавший. Политика ретраев (число попыток, backoff) — конфигурация, а не код приложения.
Когда подходит
- Async-работа из HTTP, вебхуков или cron, где сбои на следующих шагах ожидаемы
- Многошаговые задачи, где перезапуск всей задачи при сбое дорог или небезопасен
На что обратить внимание
- Повтор всей задачи с нуля перезапускает завершённые шаги — двойные письма, двойные списания, дубли записей, если обработчики не идемпотентны.
- Ретраи с фиксированным интервалом добивают и без того падающие сервисы на следующем шаге. Экспоненциальному backoff нужны аккуратная настройка и jitter — шаблон, который большинство команд копирует с ошибками.
Нагрузка и где ломается
Почему ретраи фоновых задач сложнее, чем кажется
Большинство команд начинают с fire-and-forget: поставили задачу и надеются на успех. Когда она падает, кто-то грепает логи и переигрывает вручную. В масштабе тихие сбои становятся утечкой выручки и злыми клиентами.
Самописные циклы ретраев в воркер-процессах теряют состояние при рестарте, обрабатывают задачи дважды при восстановлении после падения и прячут счётчики ретраев от дашбордов наблюдаемости.
Компромиссы
Где ломаются самодельные ретраи
Повтор всей задачи с нуля перезапускает завершённые шаги — двойные письма, двойные списания, дубли записей, если обработчики не идемпотентны.
Ретраи с фиксированным интервалом добивают и без того падающие сервисы на следующем шаге. Экспоненциальному backoff нужны аккуратная настройка и jitter — шаблон, который большинство команд копирует с ошибками.
Как помогает Inquir
Ретраи шагов пайплайна как примитив платформы
Каждый шаг пайплайна повторяется при сбое независимо. Завершённые шаги остаются в чекпоинтах — перезапускается только упавший. Политика ретраев (число попыток, backoff) — конфигурация, а не код приложения.
История выполнения показывает каждую попытку: вход, выход, длительность, текст ошибки, число ретраев. Оповещайте по доле сбоев без собственного дашборда.
Что вы получаете
Паттерны ретраев фоновых задач
Ретраи на шаг с backoff
Упавшие шаги повторяются по настраиваемой политике. Завершённые не выполняются заново при падении следующего.
Идемпотентные обработчики задач
Проектируйте обработчики с расчётом на ретраи: upsert по ID задачи, проверка перед записью, ключи дедупликации из payload триггера.
Триггер из любой точки входа
HTTP 202, подтверждение вебхука, cron-расписание или другая задача — все ставят работу в пайплайн с одной и той же семантикой ретраев.
История сбоев с поиском
Ищите упавшие прогоны по времени, функции или тексту ошибки. Переигрывайте из сохранённого payload, не повторяя исходный HTTP-запрос.
Что дальше
Как запускать фоновые задачи с ретраями на Inquir
Быстро принять, поставить durable-задачу в очередь, а упавшие шаги повторит платформа.
Принять и поставить в очередь
HTTP-обработчик или вебхук сразу возвращает 202. Вызовите global.durable.startNew() с payload задачи.
Написать идемпотентные обработчики шагов
Каждый шаг пайплайна проверяет ключ дедупликации до побочных эффектов. Возвращайте структурированный выход для следующего шага.
Настроить политику ретраев и оповещения
Задайте число попыток и backoff шага в конфигурации пайплайна. Оповещайте, когда доля сбоев превышает порог.
Пример кода
Фоновая задача с повторяемыми шагами пайплайна
HTTP-обработчик ставит работу в очередь одной строкой. Шаги пайплайна повторяются независимо при сбое на следующем шаге.
export async function handler(event) { const { userId, format } = JSON.parse(event.body || '{}'); if (!userId) return { statusCode: 400, body: JSON.stringify({ error: 'userId required' }) }; const { instanceId: jobId } = await global.durable.startNew('export-data', undefined, { userId, format }); return { statusCode: 202, body: JSON.stringify({ jobId, status: 'queued' }) }; }
export async function handler(event) { const { userId, format } = event.payload ?? {}; const existing = await db.findExport(userId, event.instanceId); if (existing) return { statusCode: 200, body: JSON.stringify({ url: existing.url }) }; const url = await generateAndUploadExport(userId, format); await db.saveExport(userId, event.instanceId, url); return { statusCode: 200, body: JSON.stringify({ url }) }; }
Когда подходит
Кому подходят фоновые задачи с ретраями
Когда это уместно
- Async-работа из HTTP, вебхуков или cron, где сбои на следующих шагах ожидаемы
- Многошаговые задачи, где перезапуск всей задачи при сбое дорог или небезопасен
Когда лучше выбрать другое
- Синхронная работа короче секунды без риска сбоя
Частые вопросы
Частые вопросы
Чем это отличается от ретраев в BullMQ?
BullMQ повторяет задачи целиком в Redis через воркер-процесс. Inquir повторяет отдельные шаги пайплайна с чекпоинтами прогресса — без Redis и флота воркеров.
Можно ли задать разную политику ретраев на шаг?
Да. Число попыток и backoff настраиваются на каждый шаг пайплайна. Шаг с нестабильным внешним API можно повторять агрессивнее, чем локальную валидацию.
Что происходит после исчерпания ретраев?
Прогон пайплайна помечается failed с полными логами. Дальше — ручной replay из истории выполнения или оповещение оператору.