GH GambleHub

Webhooks: повтори і квітування

1) Базова модель доставки

At-least-once (за замовчуванням): подія буде доставлена ≥1 раз. Гарантії рівно-один-раз досягаються ідемпотентністю приймача.
Квітування (ACK): тільки будь-яка 2xx (зазвичай 200/204) від одержувача означає успіх. Все інше трактується як відмова і веде до повтору.
Швидкий ACK: відповідайте 2xx після поміщення події в свою чергу, а не після повної бізнес-обробки.

2) Формат подій і обов'язкові заголовки

Корисне навантаження (приклад)

json
{
"id": "evt_01HXYZ",
"type": "order. created",
"occurred_at": "2025-11-03T18:10:12Z",
"sequence": 128374,
"source": "orders",
"data": { "order_id": "o_123", "amount": "49. 90", "currency": "EUR" },
"schema_version": 1
}

Заголовки відправника

`X-Webhook-Id: evt_01HXYZ' - унікальний ID події (використовуйте для дедуплікації).
`X-Webhook-Seq: 128374'- монотонна послідовність (за передплатою/темою).
`X-Signature: sha256 = <base64 (hmac_sha256 (body, secret))>'- HMAC-підпис.
`X-Retry: 0,1,2...'- номер спроби.
`X-Webhook-Version: 1'- версіонування контракту.
(опціонально) «Traceparent» - кореляція трас.

Відповідь одержувача

2xx - успішно прийнято (далі повторів з цього'id'не буде).
410 Gone - endpoint видалений/неактивний → відправник припиняє повтори і деактивує підписку.
429/5хх/таймаут - відправник повторює по політиці ретраїв.

3) Політика повторів (retries)

Рекомендовані сходи backoff (+ jitter)

'1s, 3s, 10s, 30s, 2m, 10m, 30m, 2h, 6h, 24h'( зупиняємося після ліміту, наприклад 48-72 годин).

Правила:
  • Експоненціальний backoff + випадковий jitter (± 20-30%) для уникнення «стадного ефекту».
  • Кворум помилок для тимчасових збоїв (наприклад, повтор, якщо 5xx або таймаут мережі).
  • Respect 429: ставте мінімум'min (заголовок Retry-After, наступне вікно backoff)'.

Таймаути і розміри

Таймаут з'єднання ≤ 3-5 сек; загальний таймаут відповіді ≤ 10 сек.
Розмір тіла за контрактом (наприклад, ≤ 256 KB), інакше 413 → логіка «chunking» або «pull URL».

4) Ідемпотентність і дедуплікація

Ідемпотентне застосування: обробка повторів того ж'id'повинна повертати той же результат і не змінювати стан повторно.
Дедуп-сховище на стороні одержувача: зберігати «(X-Webhook-Id, processed_at, checksum)» з TTL ≥ вікна ретраїв (24-72 год).
Композиційний ключ: якщо кілька топиків → «(subscription_id, event_id)».

5) Порядок і «exactly-once ефекти»

Гарантувати суворий порядок складно в розподілених системах. Використовуйте:
  • Partition by key: одна і та ж логічна множина (наприклад,'order _ id') завжди в один «канал» доставки.
  • Sequence: відхиляйте події зі старим'X-Webhook-Seq'і ставте їх в «parking lot» до приходу відсутніх.
Exactly-once ефекти досягаються через:
  • журнал застосованих операцій (outbox/inbox pattern),
  • транзакційне upsert по'event _ id'в БД,
  • саги/компенсації для складних процесів.

6) Вирішення помилок за статус-кодами (таблиця)

Код відповідіЗначення для відправникаДія
2xxACK отриманоВважаємо доставленим, зупиняємо ретраї
4xx (крім 410/429)Постійна помилка (payload/авторизація)Поставити в DLQ, повідомити інтеграцію
410Endpoint видалений/застарівЗупинити ретраї, деактивувати підписку
408/429Тимчасове перевантаження/таймаутПовтор по backoff/Jitter; враховувати'Retry-After '
5xxТимчасова помилка сервераПовтор по backoff/Jitter
3xxНе використовуйте редиректи для вебхуківТрактувати як помилка конфігурації

7) Безпека каналу

Підпис HMAC кожного повідомлення; перевірка на приймачі з «вікном часу» (mitm і replay-атаки).
mTLS для чутливих доменів (КУС/платежі).
IP allowlist вихідних адрес, TLS 1. 2+, HSTS.
PII-мінімізація: не надсилайте зайві персональні дані; маскуйте в логах.
Ротація секретів: два діючих ключа (active/next) і заголовок'X-Key-Id'для вказівки поточного.

8) Черги, DLQ і реплей

Події обов'язково пишуться у вихідну чергу/журнал на стороні відправника (для надійного реплея).
При перевищенні максимуму ретраїв - подія йде в DLQ (Dead Letter Queue) з причиною.
Replay API (для одержувача/оператора): повторна відправка по'id '/діапазону часу/темі, з обмеженням RPS і додатковим підписом/авторизацією.

Приклад Replay API (відправник):

POST /v1/webhooks/replay
{ "subscription_id": "sub_123", "from": "2025-11-03T00:00:00Z", "to": "2025-11-03T12:00:00Z" }
→ 202 Accepted

9) Контракт і версія

Версіонуйте подію (поле'schema _ version') і транспорт ('X-Webhook-Version').
Додавайте поля тільки як опціональні; при видаленні - мінорна міграція і перехідний період (dual-write).
Документуйте типи подій, приклади, схеми (JSON Schema), коди помилок.

10) Спостережуваність і SLO

Ключові метрики відправника:
  • 'delivery _ success _ rate'( 2хх/всі спроби),'first _ attempt _ success _ rate'
  • `retries_total`, `max_retry_age_seconds`, `dlq_count`
  • `latency_p50/p95` (occurred_at → ack_received_at)
Ключові метрики одержувача:
  • `ack_latency` (receive → 2xx), `processing_latency` (enqueue → done)
  • `duplicates_total`, `invalid_signature_total`, `out_of_order_total`
SLO приклади:

99. 9% подій отримують перший ACK ≤ 60 сек (28d).

  • DLQ ≤ 0. 1% від загального числа; реплей DLQ ≤ 24 год.

11) Таймінг і розриви мережі

Використовуйте UTC в полях часу; синхронізуйте NTP.
Відправляйте'occurred _ at'і фіксуйте'delivered _ at', щоб рахувати лаг.
При тривалих розривах мережу/endpoint → накопичуйте в черзі, обмежуйте зростання (backpressure + квоти).

12) Рекомендовані ліміти та гігієна

RPS на підписку (наприклад, 50 RPS, burst 100) + паралелізм (наприклад, 10).
Макс. тіло: 64–256 KB; для більшого - «notification + URL» і підпис на скачування.
Імена подій в'snake. case'або'dot. type` (`order. created`).
Сувора ідемпотентність write-операцій приймача.

13) Приклади: відправник і одержувач

13. 1 Відправник (псевдокод)

python def send_event(event, attempt=0):
body = json. dumps(event)
sig = hmac_sha256_base64(body, secret)
headers = {
"X-Webhook-Id": event["id"],
"X-Webhook-Seq": str(event["sequence"]),
"X-Retry": str(attempt),
"X-Signature": f"sha256={sig}",
"Content-Type": "application/json"
}
res = http. post(endpoint, body, headers, timeout=10)
if 200 <= res. status < 300:
mark_delivered(event["id"])
elif res. status == 410:
deactivate_subscription()
else:
schedule_retry(event, attempt+1) # backoff + jitter, respect 429 Retry-After

13. 2 Одержувач (псевдокод)

python
@app. post("/webhooks")
def handle():
body  = request. data headers = request. headers assert verify_hmac(body, headers["X-Signature"], secret)
evt_id = headers["X-Webhook-Id"]
if dedup_store. exists(evt_id):
return, "" 204 enqueue_for_processing (body) # fast path. dedup_store put(evt_id, ttl=723600)
return, "" 202 # or 204

14) Тестування та хаос-практики

Негативні кейси: невалідний підпис, 429/5xx, таймаут, 410, великі payload'и.
Поведінкові: out-of-order, дублікати, затримки 1-10 хвилин, розрив на 24 години.
Навантажувальні: burst 10×; перевірте backpressure і стійкість DLQ.
Контракти: JSON Schema, обов'язкові заголовки, стабільні типи подій.

15) Чек-лист впровадження

  • 2xx = ACK, і швидке повернення після enqueue
  • Експоненціальний backoff + jitter, повага'Retry-After '
  • Ідемпотентність приймача і дедуп по'X-Webhook-Id'( TTL ≥ ретраї)
  • Підписи HMAC, ротація секретів, optional mTLS
  • DLQ + Replay API, моніторинг та алерти
  • Обмеження: таймаути, RPS, розмір тіла
  • Порядок: partition by key или `sequence` + «parking lot»
  • Документація: схеми, приклади, кодування помилок, версії
  • Хаос-тести: затримки, дублі, відмова мережі, тривалий replay

16) Міні-FAQ

Чи потрібно завжди відповідати 200?
Будь-яка 2xx зараховується як успіх. 202/204 - нормальна практика для «прийнято в чергу».

Чи можна зупинити повтори?
Так, відповіддю 410 і/або через консоль/API відправника (відключення підписки).

Як бути з великими payload'ами?
Відправляйте «повідомлення + secure URL», підпишіть запит на скачування і встановіть TTL.

Як забезпечити порядок?
Partition by key + `sequence`; при розбіжності - «parking lot» і перегравання.

Підсумок

Надійні вебхуки - це чітка семантика ACK (2xx), розумні повтори з backoff + jitter, сувора ідемпотентність і дедуплікація, грамотна безпека (HMAC/mTLS), черги + DLQ + реплей, і прозора спостережуваність. Зафіксуйте контракт, введіть ліміти і метрики, регулярно проганяйте хаос-сценарії - і ваші інтеграції перестануть «сипатися» при перших же збоях.

Contact

Зв’яжіться з нами

Звертайтеся з будь-яких питань або за підтримкою.Ми завжди готові допомогти!

Розпочати інтеграцію

Email — обов’язковий. Telegram або WhatsApp — за бажанням.

Ваше ім’я необов’язково
Email необов’язково
Тема необов’язково
Повідомлення необов’язково
Telegram необов’язково
@
Якщо ви вкажете Telegram — ми відповімо й там, додатково до Email.
WhatsApp необов’язково
Формат: +код країни та номер (наприклад, +380XXXXXXXXX).

Натискаючи кнопку, ви погоджуєтесь на обробку даних.