Платформа ретраев для вебхуков: пережить повторные доставки провайдера
Stripe, GitHub и Slack повторяют доставку неудачных вебхуков часами и днями. Платформе ретраев для вебхуков нужны три слоя: быстро отсекать подделки, подтверждать в таймаутах провайдера и повторять работу на следующих шагах без дублирования побочных эффектов. Inquir даёт идемпотентность, ретраи пайплайна и трассы каждой доставки в одном serverless-стеке.
Обновлено: 2026-06-28
Кратко
Суть ответа
Платформа ретраев для вебхуков: пережить повторные доставки провайдера. Функция вебхука проверяет подпись, пишет ID события провайдера в надёжное хранилище, сразу возвращает 200 и ставит работу в пайплайн. Повторные доставки провайдера упираются в проверку идемпотентности и получают 200 без повторной обработки.
Когда подходит
- SaaS-вебхуки от Stripe, GitHub, Slack, Shopify или HubSpot с агрессивными политиками повторной доставки
- Обработчики, где работа на следующем шаге может упасть уже после того, как провайдеру ответили 200
На что обратить внимание
- Проверка «видел ли я этот ID события?» в памяти приложения не переживает рестарт и горизонтальное масштабирование. Нужны ключи идемпотентности в надёжном хранилище, записанные до любого побочного эффекта.
- Повтор всего обработчика вебхука при сбое на следующем шаге заново гоняет проверку подписи и рискует обработать событие дважды, если первая попытка успела частично.
Нагрузка и где ломается
Два вида повторов вебхуков — и оба нельзя игнорировать
Повторные доставки провайдера: Stripe повторяет до 72 часов, если эндпоинт ответил не 2xx или не успел. GitHub — 3 дня. Каждая повторная доставка — новый HTTP-запрос с тем же ID события; дубли нужно распознавать до изменения состояния.
Ретраи на следующем шаге: обработчик быстро ответил 200, но API выполнения заказа упал. Без платформы ретраев этот сбой тихий — или вы вручную переигрываете событие по логам. Ретраи шагов пайплайна решают это, не заставляя провайдера присылать событие заново.
Компромиссы
Почему самописные ретраи ломаются в масштабе
Проверка «видел ли я этот ID события?» в памяти приложения не переживает рестарт и горизонтальное масштабирование. Нужны ключи идемпотентности в надёжном хранилище, записанные до любого побочного эффекта.
Повтор всего обработчика вебхука при сбое на следующем шаге заново гоняет проверку подписи и рискует обработать событие дважды, если первая попытка успела частично.
Как помогает Inquir
Идемпотентный вход + пайплайны с ретраями
Функция вебхука проверяет подпись, пишет ID события провайдера в надёжное хранилище, сразу возвращает 200 и ставит работу в пайплайн. Повторные доставки провайдера упираются в проверку идемпотентности и получают 200 без повторной обработки.
Шаги пайплайна повторяются независимо с экспоненциальным backoff. Трассы выполнения показывают каждую попытку доставки, каждый ретрай шага и итог — дежурный отвечает на вопрос «обработано ли это событие?» за секунды.
Что вы получаете
Возможности платформы ретраев для вебхуков
Идемпотентность по событиям провайдера
Делайте upsert ID события до изменений. Повторные доставки от Stripe, GitHub или Slack получают 200 без побочных эффектов.
Быстрое подтверждение под давлением таймаута
Возвращайте 200 в окне 3 с у Slack, лимите 30 с у Stripe и ожиданиях GitHub — тяжёлая работа идёт в пайплайнах.
Ретраи следующих шагов
Шаги пайплайна повторяют упавшие вызовы API, записи в базу и уведомления, не вызывая заново функцию приёма вебхука.
Трассы выполнения на каждую доставку
Смотрите заголовки, тайминги, число ретраев и выходы шагов по каждой доставке вебхука — вместо чёрного ящика логов воркера.
Что дальше
Как собрать платформу ретраев для вебхуков на Inquir
Разделите обработку повторных доставок провайдера (идемпотентность на входе) и ретраи следующих шагов (политика шагов пайплайна).
Проверить и записать ID события
Проверьте HMAC по сырому телу, сделайте upsert ID события провайдера в надёжное хранилище, верните 200 — даже при повторной доставке.
Поставить надёжную задачу в очередь
Вызовите global.durable.startNew() с разобранным payload события. HTTP-ответ завершается до начала работы на следующих шагах.
Повторять упавшие шаги, а не вебхук
Настройте политику ретраев шагов пайплайна для сбоев на следующих шагах. Завершённые шаги не перезапускаются при падении следующего.
Пример кода
Идемпотентный приём вебхука с передачей в пайплайн
Повторные доставки провайдера упираются в проверку идемпотентности. Сбои на следующих шагах повторяются на уровне шага пайплайна.
export async function handler(event) { const rawBody = event.body ?? ''; if (!verifyStripeSignature(rawBody, event.headers['stripe-signature'])) { return { statusCode: 400, body: 'invalid signature' }; } const evt = JSON.parse(rawBody); const isNew = await db.tryInsertWebhookEvent(evt.id, evt.type); if (!isNew) return { statusCode: 200, body: 'already processed' }; await global.durable.startNew('stripe-fulfillment', undefined, { eventId: evt.id, type: evt.type, object: evt.data.object, }); return { statusCode: 200, body: 'accepted' }; }
Когда подходит
Кому подходит платформа ретраев для вебхуков
Когда это уместно
- SaaS-вебхуки от Stripe, GitHub, Slack, Shopify или HubSpot с агрессивными политиками повторной доставки
- Обработчики, где работа на следующем шаге может упасть уже после того, как провайдеру ответили 200
Когда лучше выбрать другое
- Вебхуки, которые пересылаются в стороннюю iPaaS без своего рантайма
Частые вопросы
Частые вопросы
Как долго провайдеры повторяют доставку?
Stripe: до 72 часов с экспоненциальным backoff. GitHub: до 3 дней. Slack ждёт ответ в течение 3 секунд, иначе помечает приложение медленным. Закладывайте и быстрое подтверждение, и повторные доставки.
Что если шаг пайплайна исчерпал ретраи?
Прогон пайплайна помечается failed с полными логами шагов. Оповещайте по доле сбоев; переигрывайте вручную из истории выполнения по сохранённому payload события.
Нужна ли отдельная dead-letter-очередь?
Нет — у очереди durable-задач есть встроенный dead-letter-путь: доставка, исчерпавшая ретраи, попадает в состояние dead-letter с последней ошибкой для разбора и replay, а упавшие прогоны пайплайна остаются доступны для поиска в истории выполнения. Ничего отдельного разворачивать не нужно.