GH GambleHub

Гарантії доставки вебхуків

Вебхукі - асинхронні повідомлення «з системи до передплатника» по HTTP (S). Мережа ненадійна: відповіді втрачаються, пакети приходять дублікатами або поза порядком. Тому гарантії доставки будуються не «по TCP», а на рівні протоколу вебхуків і доменної ідемпотентності.

Ключова мета: забезпечити at-least-once доставку з порядком по ключу (там, де необхідно), дати передплатнику матеріали для ідемпотентної обробки та інструмент reconcile для відновлень.


1) Рівні гарантій

Best-effort - одноразова спроба, без ретраїв. Прийнятно тільки для «неважливих» подій.
At-least-once (рекомендується) - можливі дублікати і out-of-order, але подія буде доставлена за умови доступності передплатника в розумний термін.
Effectively-exactly-once (на рівні ефекту) - досягається комбінацією ідемпотентності і dedup-сховища на стороні передплатника/відправника. На транспорті HTTP «exactly-once» неможливо.


2) Контракт вебхука: мінімально необхідне

Заголовки (приклад):

X-Webhook-Id: 5d1e6a1b-4f7d-4a3d-8b3a-6c2b2f0f3f21  # глобальный ID события
X-Delivery-Attempt: 3                 # номер попытки
X-Event-Type: payment.authorized.v1          # тип/версия
X-Event-Time: 2025-10-31T12:34:56Z          # ISO8601
X-Partition-Key: psp_tx_987654            # ключ порядка
X-Seq: 418                      # монотонный номер по ключу
X-Signature-Alg: HMAC-SHA256
X-Signature: t=1730378096,v1=hex(hmac(secret, t        body))
Content-Type: application/json
Тіло (приклад):
json
{
"id": "5d1e6a1b-4f7d-4a3d-8b3a-6c2b2f0f3f21",
"type": "payment.authorized.v1",
"occurred_at": "2025-10-31T12:34:56Z",
"partition_key": "psp_tx_987654",
"sequence": 418,
"data": {
"payment_id": "psp_tx_987654",
"amount": "10.00",
"currency": "EUR",
"status": "AUTHORIZED"
},
"schema_version": 1
}

Вимога до одержувача: відповідати швидко «2xx» після буферизації і валідації підпису, а бізнес-обробку робити асинхронно.


3) Порядок і причинність

Порядок за ключем: гарантія «не поїде» тільки всередині одного'partition _ key'( напр.,'player _ id','wallet _ id','psp _ tx _ id').
Глобальний порядок не гарантується.
На стороні відправника - черга з серіалізацією по ключу (один споживач/шардинг), на стороні одержувача - inbox з'( source, event_id)'і опціонально очікування пропущених'seq'.

Якщо пропуски критичні - надайте pull-API'GET/events? after = checkpoint'для статусу «наздогнати і звіритися».


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

Кожен вебхук несе стабільний'X-Webhook-Id'.
Одержувач зберігає'inbox (event_id)': PK — `source + event_id`; повтори → no-op.
Побічні ефекти (запис в БД/гаманець) виконуються тільки один раз при першому «баченні» події.
Для команд «з ефектом» використовуйте Idempotency-Key і кеш результатів на час вікна ретраїв.


5) Ретраї, backoff і вікна

Політика ретраїв (референс):
  • Ретраїти на'5xx/timeout/connection error/409-Conflict (retryable )/429'.
  • Не ретраїти на «4xx» крім «409/423/429» (і тільки при узгодженій семантиці).
  • Експоненціальний backoff + full jitter: 0. 5s, 1s, 2s, 4s, 8s, … до'max = 10-15 хв'; TTL вікна ретраїв: наприклад, 72 години.
  • Поважати'Retry-After'у одержувача.
  • Мати загальний дедлайн: «визнати подію не доставленою» і перевести її в DLQ.
yaml retry:
initial_ms: 500 multiplier: 2.0 jitter: full max_delay_ms: 900000 ttl: 72h retry_on: [TIMEOUT, 5xx, 429]

6) DLQ и redrive

DLQ - «кладовище» отруйних або закінчених по TTL подій з повною метаінформацією (пейлоад, заголовки, помилки, спроби, хеші).
Веб-консоль/API для redrive (точкова повторна доставка) з опціональною правкою endpoint/секрету.
Rate-limited redrive і batch-redrive з пріоритезацією.


7) Безпека

mTLS (по можливості) або TLS 1. 2+.

Підпис тіла (HMAC з секретом per tenant/endpoint). Верифікація:

1. Витягти't'( timestamp) з заголовка, перевірити ковзне вікно (наприклад, ± 5 хв).

2. Відновити рядок підпису'tbody', порівняти HMAC в constant-time.
Anti-replay: зберігати «(event_id, t)» і відхиляти занадто старі/повторні запити.
Ротація секретів: підтримка двох активних секретів на період ротації.
Додатково: IP-allowlist, заголовок'User-Agent', дедикація origin-IP.

8) Квоти, rate limits і справедливість

Fair-Queue per tenant/subscriber: щоб один підписник/тенант не забив загальний пул.
Квоти і burst-ліміти на вихідний трафік і per-endpoint.
Реакція на «429»: шанувати'Retry-After', тротлити потік; при тривалому лімітуванні - degrade (відправка тільки критичних типів подій).


9) Життєвий цикл підписки

Register/Verify: POST endpoint → challenge/response або out-of-band підтвердження.
Lease (за бажанням): підпис діє до «valid _ to»; пролонгація - явна.
Secret rotation: `current_secret`, `next_secret` с `switch_at`.
Test ping: штучна подія для перевірки маршруту перед включенням основних топіків.
Health-проби: періодичні HEAD/GET з перевіркою latency і TLS профілю.


10) Еволюція схем (версії подій)

Версіонування типу події: `payment. authorized. v1` → `…v2`.
Еволюція - additive (нові поля → MINOR версії API), breaking → новий тип.
Регістр схем (JSON-Schema/Avro/Protobuf) + автоматична валідація перед відправкою.
Заголовок'X-Event-Type'і поле'schema _ version'в тілі - обидва обов'язкові.


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

Метрики (за типом/тенанту/передплатнику):
  • `deliveries_total`, `2xx/4xx/5xx_rate`, `timeout_rate`, `signature_fail_rate`.
  • 'attempts _ avg','p50/p95/p99 _ delivery _ latency _ ms'( від публікації до 2xx).
  • `dedup_rate`, `out_of_order_rate`, `dlq_rate`, `redrive_success_rate`.
  • `queue_depth`, `oldest_in_queue_ms`, `throttle_events`.
SLO (референс):
  • Частка доставок ≤ 60 c (p95) - 99. 5% для критичних подій.
  • DLQ ≤ 0. 1% за 24 год.
  • Signature failures ≤ 0. 05%.

Логи/трейсинг: `event_id`, `partition_key`, `seq`, `attempt`, `endpoint`, `tenant_id`, `schema_version`, `trace_id`.


12) Референсний алгоритм відправника

1. Записати подію в транзакційний outbox.
2. Визначити partition_key і seq; помістити в чергу.
3. Воркер бере по ключу, формує запит, підписує, відправляє з таймаутами (connect/read).
4. При «2xx» - визнати доставленим, зафіксувати латентність і seq-чекпоінт.
5. При'429/5xx/timeout'- ретрай згідно з політикою.
6. По TTL → DLQ і алерт.


13) Референсний обробник (одержувач)

1. Прийняти запит, перевірити TLS/proto.
2. Валідація підпису і вікна часу.
3. Швидкий ACK 2xx (після синхронного запису в локальний inbox/чергу).
4. Асинхронний воркер читає «inbox», перевіряє «event _ id» (дедуп), при необхідності - впорядковує по «seq» всередині «partition _ key».
5. Виконує ефекти, пише «offset/seq чекпоінт» для reconcile.
6. У разі помилки - локальні ретраї; «отруйні» завдання → локальна DLQ з алертами.


14) Reconcile (пулл-контур)

Для «непробивних» інцидентів:
  • `GET /events? partition_key=...&after_seq=...&limit=...' - віддати всі пропущені.
  • Токен-чекпоінт: 'after = opaque _ token'замість seq.
  • Ідемпотентний redelivery: ті ж'event _ id', той же підпис по новому't'.

15) Корисні заголовки та коди

2xx - прийняв (навіть якщо бізнес-обробка пізніше).
410 Gone - endpoint закритий (відправник припиняє доставку і позначає підписку як «в архів»).
409/423 - тимчасове блокування ресурсу → ретрай розумний.
429 - занадто часто → троттл і backoff.
400/401/403/404 - конфігураційна помилка; зупинити ретраї, відкрити тікет.


16) Мульти-тенант і регіони

Окремі черги та ліміти per tenant/endpoint.
Data residency: відправка з регіону даних; наскрізні заголовки'X-Tenant','X-Region'.
Ізоляція збоїв: падіння одного підписувача не впливає на інших (separate pools).


17) Тестування

Contract tests: фіксовані приклади тіл/підписів, перевірка валідації.
Chaos: дроп/дублікати, shuffle порядку, затримки мережі,'RST','TLS'-помилки.
Load: burst-шторму, завмер p95/p99.
Security: анти-реплей, застарілі timestamp, неправильні секрети, ротація.
DR/Replay: масовий redrive з DLQ в ізольованому стенді.


18) Плейбуки (runbooks)

1. Зростання'signature _ fail _ rate '

Перевірити дрейф годинника, що минув'tolerance', ротацію секретів; тимчасово увімкнути «dual secret».

2. Черга старіє ('oldest _ in _ queue _ ms'↑)

Збільшити воркери, включити пріоритизацію критичних топіків, тимчасово знизити частоту «галасливих» типів.

3. Шторм «429» у передплатника

Увімкнути тротлінг і паузи між спробами; зрушити менш критичні типи подій.

4. Масові'5xx '

Відкрити circuit-breaker для конкретного endpoint, перевести в режим defer & batch; сигнал передплатнику.

5. Заповнення DLQ

Зупинити не-критичну публікацію, включити batch-redrive з низьким RPS, підняти алерти власникам підписок.


19) Типові помилки

Синхронна важка обробка до відповіді 2xx → ретраї і дублікати.
Немає підпису тіла/вікна часу → вразливість до підміни/реплею.
Відсутність'event _ id'і'inbox'→ неможливо зробити ідемпотентність.
Спроба «глобального порядку» → вічні блокування черг.
Ретраї без jitter/лімітів → посилення інциденту (thundering herd).
Єдиний загальний пул на всіх передплатників → «галасливий» кладе всіх.


20) Чек-лист перед продом

  • Контракт: `event_id`, `partition_key`, `seq`, `event_type. vN', підпис HMAC і timestamp.
  • Відправник: outbox, серіалізація за ключем, ретраї з backoff + jitter, TTL, DLQ і redrive.
  • Одержувач: швидкий запис в inbox + 2xx; ідемпотентна обробка; локальна DLQ.
  • Безпека: TLS, підписи, анти-реплей, dual-secret, ротація.
  • Квоти/ліміти: fair-queue per tenant/endpoint, повага'Retry-After'.
  • Reconcile API і чекпоінти; документація для передплатників.
  • Спостережуваність: p95/потоки/помилки/DLQ, трасування по'event _ id'.
  • Версіонування подій і політика еволюції схем.
  • Плейбуки інцидентів і «кнопка» глобального пауза/розморожування.

Висновок

Надійні вебхуки - це протокол поверх HTTP, а не просто «POST з JSON». Чіткий контракт (ID, ключ порядку, підпис), ідемпотентність, ретраї з jitter, справедлива черга і добре налагоджені плейбуки перетворюють «кращий-випадок» в передбачуваний і вимірюваний механізм доставки. Будуйте at-least-once + порядок за ключем + reconcile, і система спокійно переживе мережу, піки навантаження і людські помилки.

Contact

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

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

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

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

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

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