Inquir Compute · вебхуки

Платформа повторов вебхуков: пережить повторные доставки провайдера

Stripe, GitHub и Slack повторяют неудачные вебхуки часами и днями. Нужны три слоя: отсечь подделки, ACK в лимите провайдера и повтор downstream без дублирования эффектов. Inquir даёт идемпотентность, повторы пайплайна и трассировки каждой доставки.

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

Суть ответа

Платформа повторов вебхуков: пережить повторные доставки провайдера. Функция вебхука проверяет подпись, пишет event ID провайдера в durable-хранилище, сразу возвращает 200 и ставит работу в пайплайн. Повторы провайдера упираются в idempotency-check и получают 200 без re-processing.

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

  • Вебхуки Stripe, GitHub, Slack, Shopify, HubSpot с агрессивными retry
  • Downstream может упасть после 200 провайдеру

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

  • Проверка «видел ли event ID?» в памяти процесса не переживает рестарт и горизонтальное масштабирование. Нужны durable-ключи идемпотентности до любого side effect.
  • Повтор всего webhook-handler при сбое downstream снова гоняет верификацию подписи и рискует double-processing, если первая попытка частично успела.

Два вида повторов вебхуков — оба больно игнорировать

Повторы провайдера: Stripe до 72 часов при non-2xx или таймауте. GitHub — до 3 дней. Каждая redelivery — новый HTTP с тем же event ID; дубликаты нужно ловить до мутаций.

Повторы downstream: handler уже ответил 200, но fulfillment API упал. Без платформы повторов — тихий сбой или ручной replay из логов. Повторы шагов пайплайна решают это без re-trigger провайдера.

Почему ad-hoc retry ломается в масштабе

Проверка «видел ли event ID?» в памяти процесса не переживает рестарт и горизонтальное масштабирование. Нужны durable-ключи идемпотентности до любого side effect.

Повтор всего webhook-handler при сбое downstream снова гоняет верификацию подписи и рискует double-processing, если первая попытка частично успела.

Идемпотентный ingress + retriable-пайплайны

Функция вебхука проверяет подпись, пишет event ID провайдера в durable-хранилище, сразу возвращает 200 и ставит работу в пайплайн. Повторы провайдера упираются в idempotency-check и получают 200 без re-processing.

Шаги пайплайна повторяются независимо с exponential backoff. Трассировки показывают каждую доставку, каждый retry шага и итог — on-call отвечает «обработано ли событие?» за секунды.

Возможности платформы повторов вебхуков

Идемпотентность провайдера

Upsert event ID до мутаций. Дубликаты Stripe, GitHub, Slack — 200 без побочных эффектов.

Быстрый ACK под давлением таймаута

200 в окне Slack 3 с, лимите Stripe 30 с и ожиданиях GitHub — тяжёлое в пайплайнах.

Повторы шагов downstream

Шаги пайплайна повторяют упавшие API, записи в БД и нотификации без повторного вызова ingress-функции.

Трассировки на доставку

Заголовки, время, счётчик retry и выходы шагов для каждой доставки — не чёрный ящик воркера.

Как собрать платформу повторов вебхуков на Inquir

Разделите повторы провайдера (idempotency на ingress) и downstream (политика шагов пайплайна).

1

Проверить и записать event ID

HMAC по сырому body, upsert event ID провайдера, 200 — даже при duplicate delivery.

2

Поставить durable-работу

global.durable.startNew() с разобранным payload. HTTP завершается до начала downstream.

3

Повторять шаги, не вебхук

Политика retry на шагах пайплайна для downstream. Завершённые шаги не перезапускаются при падении следующего.

Идемпотентный ingress вебхука с передачей в пайплайн

Повторы провайдера — idempotency-check. Сбои downstream — retry на уровне шага пайплайна.

webhooks/stripe-retry-safe.mjs
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' };
}

Когда нужна платформа повторов вебхуков

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

  • Вебхуки Stripe, GitHub, Slack, Shopify, HubSpot с агрессивными retry
  • Downstream может упасть после 200 провайдеру

Когда лучше не трогать

  • Вебхуки уходят в чужую iPaaS без своей среды выполнения

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

Как долго провайдеры повторяют?

Stripe: до 72 ч с backoff. GitHub: до 3 дней. Slack ждёт ответ ~3 с. Закладывайте быстрый ACK и duplicate delivery.

Если исчерпаны retry шага?

Прогон пайплайна failed с полными логами. Алерт по failure rate; ручной replay из истории по сохранённому payload.

Нужна отдельная dead-letter очередь?

Failed-прогоны пайплайна — DLQ с поиском в истории. Отдельную инфраструктуру DLQ поднимать не нужно.