Сценарий

Фоновые задачи на той же платформе, что и API

Отвечайте браузеру и мобильному клиенту за миллисекунды, а долгую работу выносите в пайплайны и очередь задач: ретраи при сбоях, идемпотентные записи и трассировки — как у синхронных вызовов.

Обновлено: 2026-06-28

Суть ответа

Фоновые задачи на той же платформе, что и API. Функции становятся шагами пайплайна; платформа ведёт их выполнение так же, как синхронные вызовы, — фоновые задачи остаются доступными для поиска.

Когда подходит и когда нет

  • Работа дольше нескольких секунд
  • Всплески нагрузки
  • Внешние API с непредсказуемой задержкой

На что обратить внимание

  • Каждый сервис, изобретающий свою группу обработчиков в Redis, операционно расходится с тем, как работают остальные ваши serverless-функции.
  • Без общей наблюдаемости фоновые задачи и пайплайны становятся чёрным ящиком рядом с REST-эндпоинтами.

Почему долгие HTTP-запросы ломают асинхронную работу

Долгая работа в потоке запроса упирается в таймауты API-шлюза и раздражает пользователей ещё до старта асинхронной задачи.

Шторм ретраев дублирует побочные эффекты, если хендлер фоновой задачи не идемпотентен.

Почему самописные очереди прячут сбои

Каждый сервис, изобретающий свою группу обработчиков в Redis, операционно расходится с тем, как работают остальные ваши serverless-функции.

Без общей наблюдаемости фоновые задачи и пайплайны становятся чёрным ящиком рядом с REST-эндпоинтами.

Одна поверхность для HTTP, async-задач и пайплайнов

Функции становятся шагами пайплайна; платформа ведёт их выполнение так же, как синхронные вызовы, — фоновые задачи остаются доступными для поиска.

Переиспользуйте секреты и сетевые настройки и для онлайн-трафика, и для офлайн-пайплайнов.

Таймаут HTTP-запроса и таймаут фоновой задачи

Фоновые задачи работают, когда HTTP перестаёт нести минуты работы. API-шлюз задаёт таймаут запроса; шаги пайплайна и задачи в очереди получают свой бюджет выполнения после того, как клиент освобождён.

Таймаут HTTP-запроса и таймаут фоновой задачи
КритерийТаймаут HTTP-запросаТаймаут фоновой задачи / шага пайплайна
Что ограничиваетОткрытое соединение клиент → шлюз → хендлер до отправки ответаВызов шага пайплайна или задачи в очереди после возврата HTTP-хендлера
Типичный потолокСекунды — ~15 минут (например, Vercel 60–300 с, Lambda 900 с, Workers ~30 с CPU)Таймаут на шаг — дольше HTTP-лимитов; цепочка шагов для многочасовой работы
Клиент ждёт?Да — сокет открыт, пока хендлер не завершится или не сработает таймаутНет — клиент получает 202 или ID задачи; работа продолжается асинхронно
РетраиПровайдер может повторить весь HTTP-запрос — риск дублирования побочных эффектовРетраи по шагам с идемпотентными хендлерами, независимо от ACK-ответа
НаблюдаемостьТолько логи запросов; оборванные прогоны — 504 или таймауты шлюзаИстория выполнения по шагам — рядом с синхронными вызовами, с поиском
Лучше подходит дляВалидация, аутентификация, быстрые чтения, постановка в очередьЭкспорты, массовая синхронизация, ML-пайплайны, многоэтапный ETL
Паттерн InquirHTTP-хендлер валидирует, вызывает global.durable.startNew(), возвращает 202Шаг пайплайна выполняется с общими секретами и тем же каталогом функций

Паттерны фоновых задач, которые стоит стандартизировать

Веерная постановка

Одно событие — много задач с ясным владельцем.

Компенсация

Откат или эскалация при частичных сбоях.

Ограничение нагрузки

Регулируйте параллелизм под хрупкий приёмник.

Как проектировать фоновые задачи на Inquir Compute

1

Описать полезную нагрузку

Версионируйте схемы, чтобы обновления не ломали уже идущие задачи.

2

Сделать идемпотентным

Защита записей стабильными ключами.

3

Наблюдать

Сигналы на отложенные и проблемные сообщения, если платформа это показывает.

HTTP-ответ сразу, тяжёлая работа — в async-задаче

HTTP-хендлер возвращает 202 немедленно, не удерживая соединение. Хендлер задачи подхватывает работу с теми же секретами и наблюдаемостью.

api/export.mjs (HTTP handler)
export async function handler(event) {
  const { reportId, userId } = JSON.parse(event.body || '{}');
  if (!reportId) return { statusCode: 400, body: JSON.stringify({ error: 'reportId required' }) };
  // Enqueue the slow export job — returns immediately
  const { instanceId: jobId } = await global.durable.startNew('export-report', undefined, { reportId, userId });
  // Client polls GET /export-status/:jobId or receives a webhook when done
  return { statusCode: 202, body: JSON.stringify({ jobId }) };
}
jobs/export-report.mjs (pipeline step)
export async function handler(event) {
  const { reportId, userId } = event.payload;
  // Idempotency key — safe to retry
  const existing = await db.exports.findByReportAndUser(reportId, userId);
  if (existing?.status === 'done') return { url: existing.url };
  const rows = await buildReport(reportId);
  const url = await storage.upload(rows, { key: `reports/${reportId}.csv` });
  await db.exports.upsert({ reportId, userId, url, status: 'done' });
  await notify(userId, { url });
  return { url };
}

Выбирайте async, когда…

Когда это уместно

  • Работа дольше нескольких секунд
  • Всплески нагрузки
  • Внешние API с непредсказуемой задержкой

Когда лучше выбрать другое

  • Мгновенные чтения в рамках ваших соглашений по времени ответа

Вопросы и ответы

Достижима ли семантика «ровно один раз»?

Ориентируйтесь на идемпотентные хендлеры и ключи дедупликации; «ровно один раз» через сеть и хранилище на практике редко — проектируйте безопасно для как минимум одной доставки.

Когда отвечать HTTP 202?

Когда работа поставлена в очередь и есть идентификатор задачи или запуска — лучше, чем держать соединение до конца длинного экспорта.

Связь с расписаниями и вебхуками?

Пайплайны стартуют от расписания, HTTP, ручного или событийного триггера; вебхук может ответить 200 и поставить задачу в очередь — разные входы, та же схема оркестрации.