Фоновые задачи с ретраями — без флота воркеров
Фоновые задачи падают: API таймаутят, база блокируется, сеть моргает. Нужны backoff на шаг, идемпотентные хендлеры и история сбоев с поиском — а не while-цикл в воркере. Пайплайны Inquir автоматически повторяют упавшие шаги, сохраняя завершённую работу в чекпоинтах.
Обновлено: 2026-06-28
Кратко
Суть ответа
Фоновые задачи с ретраями — без флота воркеров. Каждый шаг пайплайна повторяется при сбое независимо. Завершённые шаги остаются в чекпоинтах — перезапускается только упавший. Политика ретраев — это конфигурация, а не код приложения.
Когда подходит и когда нет
- Async из HTTP, вебхуков или cron, где сбои downstream ожидаемы
- Многошаговые задачи, где повтор всей job дорог или небезопасен
На что обратить внимание
- Повтор всей задачи с нуля перезапускает завершённые шаги — двойные письма, списания, записи без идемпотентности.
- Повторы с фиксированным интервалом только добивают и без того перегруженный downstream-сервис. Exponential backoff с jitter — шаблонный код, который часто копируют с ошибками.
Ситуация: нагрузка и где обычно ломается
Почему ретраи фоновых задач сложнее, чем кажется
Часто начинают с fire-and-forget: поставили задачу, надеются на успех. При сбое — grep логов и ручной replay. В масштабе тихие сбои становятся потерей выручки.
Самописные retry-циклы в воркерах теряют состояние при рестарте, обрабатывают задачи дважды при восстановлении после сбоя и прячут счётчики ретраев от дашбордов наблюдаемости.
Компромиссы
Где ломаются самодельные ретраи
Повтор всей задачи с нуля перезапускает завершённые шаги — двойные письма, списания, записи без идемпотентности.
Повторы с фиксированным интервалом только добивают и без того перегруженный downstream-сервис. Exponential backoff с jitter — шаблонный код, который часто копируют с ошибками.
Как Inquir помогает в этом сценарии
Ретраи шагов пайплайна как примитив платформы
Каждый шаг пайплайна повторяется при сбое независимо. Завершённые шаги остаются в чекпоинтах — перезапускается только упавший. Политика ретраев — это конфигурация, а не код приложения.
История выполнения показывает каждую попытку: вход, выход, длительность, текст ошибки и число ретраев. Алерты по failure rate — без собственного дашборда.
Что вы получаете на платформе
Паттерны ретраев для фоновых задач
Ретраи на шаг с backoff
Упавшие шаги повторяются по настраиваемой политике. Завершённые не выполняются заново при падении следующего.
Идемпотентные хендлеры
Upsert по job ID, проверка перед записью, dedupe-ключи из payload триггера — хендлеры спокойно переживают повторы.
Триггер из любой точки входа
HTTP 202, ACK вебхука, cron или другая задача — одна и та же семантика ретраев.
История сбоев с поиском
Ищите failed-прогоны по времени, функции или тексту ошибки. Replay из сохранённого payload без повторного HTTP-запроса.
Что сделать дальше, по шагам
Как запускать фоновые задачи с ретраями на Inquir
Быстро принять, поставить durable-работу, платформа повторяет упавшие шаги.
Принять и поставить в очередь
HTTP или вебхук возвращает 202. global.durable.startNew() с payload задачи.
Идемпотентные шаги
Каждый шаг проверяет dedupe-key до side effects. Структурированный выход для следующего шага.
Политика ретраев и алерты
Задайте число ретраев и backoff в конфиге пайплайна. Алерт срабатывает при превышении порога failure rate.
Пример кода
Фоновая задача с retriable-шагами пайплайна
HTTP-хендлер ставит работу одной строкой. Шаги пайплайна повторяются независимо при сбое downstream.
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, где сбои downstream ожидаемы
- Многошаговые задачи, где повтор всей job дорог или небезопасен
Когда лучше выбрать другое
- Синхронная работа <1 с без риска сбоя
Вопросы и ответы
Вопросы и ответы
Чем это отличается от ретраев в BullMQ?
BullMQ повторяет целые задачи в Redis через worker-процесс. Inquir повторяет отдельные шаги пайплайна с чекпоинтами прогресса — без Redis и флота воркеров.
Можно ли задать разную политику ретраев на шаг?
Да. Число попыток и backoff настраиваются на каждый шаг. Нестабильный внешний API можно повторять агрессивнее, чем локальную валидацию.
Что происходит после исчерпания ретраев?
Прогон пайплайна помечается failed с полными логами. Дальше — ручной replay из истории выполнения или алерт оператору.