Webhooks (Асинхронні вебхуки)(Вебхуки: Асинхронна взаємодія сервісів)
Архітектурний патерн асинхронної міжсервісної взаємодії (Event-driven Push), за якого провайдер події надсилає HTTP POST-запит із даними на зареєстрований URL споживача при настанні системної події.
1. Огляд концепції та системна проблема
Традиційна інтеграція систем через постійне опитування (Polling / Short Polling) страждає від двох взаємовиключних проблем:
- Висока затримка реакції (Latency): Якщо клієнт перевіряє зміни кожні 60 секунд, дані доставляються в середньому із запізненням у 30 секунд.
- Колосальне марнування обчислювальних ресурсів: 99% HTTP-запитів повертають порожню відповідь
304 Not Modifiedабо[], перевантажуючи базу даних та мережевий стек.
Webhooks (Зворотні виклики через HTTP) змінюють парадигму з Pull на Push. Замість того щоб запитувати: "Чи є нові дані?", споживач реєструє свій URL (Webhook Listener). Щойно в системі провайдера трапляється подія (успішна транзакція Stripe, новий комміт у GitHub, вхідне повідомлення Telegram), провайдер надсилає HTTP POST-запит із JSON payload безпосередньо на сервер підписника.
Традиційний Polling (Марнування ресурсів):
Клієнт ---> GET /events?since=... ---> Сервер (Порожньо: [])
Клієнт ---> GET /events?since=... ---> Сервер (Порожньо: [])
Клієнт ---> GET /events?since=... ---> Сервер (Нова подія!)
Event-Driven Webhook (Миттєвий Push):
Провайдер подій (Stripe / GitHub / Telegram)
|
| Подія: charge.succeeded (Event Payload + HMAC підпис)
| HTTP POST https://api.mysite.com/webhooks/stripe
v
Споживач (Валідація підпису -> 200 OK -> Фонова черга RabbitMQ/Redis)
2. Архітектурна таксономія та ментальна модель
Життєвий цикл вебхука спирається на три архітектурні опори:
- Криптографічна автентифікація (HMAC Signature):
- Провайдер генерує криптографічний хеш від тіла запиту (
raw body) за допомогою спільного секретного ключа (Webhook Secret), додаючи його в заголовок (наприклад,Stripe-SignatureабоX-Hub-Signature-256). - Споживач обчислює такий самий хеш і валідує його, виключаючи ризик підробки запиту зловмисником.
- Провайдер генерує криптографічний хеш від тіла запиту (
- Ідемпотентність та дедуплікація (Idempotency Engine):
- Кожна подія має глобальний унікальний ID (
evt_xxxxxxxxxx). - Споживач атомарно перевіряє наявність ID у кеші/БД (наприклад, через
INSERT ... ON CONFLICT DO NOTHINGабо RedisSET key NX EX 86400).
- Кожна подія має глобальний унікальний ID (
- Політика гарантованої доставки та повторів (Retry & Dead-Letter Queue):
- У разі недоступності сервера споживача провайдер повторює запити за експоненціальною шкалою (Exponential Backoff з джитером): через 5 хв, 30 хв, 2 год, 12 год.
- Події, що не вдалося обробити після максимальної кількості спроб, направляються в Dead-Letter Queue (DLQ) для ручного аналізу інженерами.
3. Технічний пайплайн та внутрішня механіка
Виробничий обробник із верифікацією HMAC (Node.js / Express / TypeScript)
[!IMPORTANT] Для перевірки підпису необхідно отримувати необроблене тіло запиту (
raw buffer), а не розпарсений об'єктreq.body, інакше хеш не зійдеться через розбіжності пробілів і сортування ключів JSON.
import express, { Request, Response } from "express";
import crypto from "crypto";
const app = express();
// Отримання raw buffer для ендпоінтів вебхуків
app.post(
"/api/v1/stripe-webhook",
express.raw({ type: "application/json" }),
async (req: Request, res: Response) => {
const signature = req.headers["stripe-signature"] as string;
const secret = process.env.STRIPE_WEBHOOK_SECRET!;
if (!signature) {
return res.status(400).send("Missing signature header");
}
// 1. Криптографічна валідація підпису через HMAC SHA-256
const computedHmac = crypto
.createHmac("sha256", secret)
.update(req.body)
.digest("hex");
// Безпечне порівняння за фіксований час
const isValid = crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(computedHmac)
);
if (!isValid) {
return res.status(401).send("Invalid signature");
}
const payload = JSON.parse(req.body.toString());
const eventId = payload.id;
// 2. Ідемпотентна перевірка дедуплікації
const isNew = await redis.set(`webhook:processed:${eventId}`, "1", "NX", "EX", 86400);
if (!isNew) {
// Подію вже оброблено — повертаємо 200 OK без повторного виконання
return res.status(200).json({ status: "already_processed" });
}
// 3. Відправка важкої роботи в чергу BullMQ
await eventQueue.add("process_payment", payload);
// 4. Миттєве підтвердження отримання
return res.status(200).json({ received: true });
}
);
4. Практичні інженерні сценарії в продакшені
01. Платіжний шлюз для AI SaaS (Stripe / Paddle / LiqPay)
Користувач сплачує підписку на Pro-план. Платіжна система генерує подію invoice.payment_succeeded. Вебхук миттєво оновлює статус користувача в базі даних, скидає ліміти токенів у Redis та надсилає вітальний лист, дозволяючи користувачеві продовжити роботу без перезавантаження сторінки.
02. Тригер автономного CI/CD пайплайну (GitHub Webhooks)
Інженер виконує git push у гілку main. GitHub надсилає payload із хешем комміту на власний сервер Coolify або ArgoCD. Сервер перевіряє секрет, клонує змінений код, запускає unit-тести в ізольованому Docker-контейнері та оновлює production-сервіс за стратегією Blue/Green.
03. Асинхронний збір результатів інференсу важких AI-моделей
При виклику моделей генерації відео (Runway, Kling) або тренування LoRA запит триває кілька хвилин. Замість тримання відкритого HTTP-з'єднання клієнт передає webhook_url. Щойно кластер GPU завершує генерацію, він надсилає вебхук із фінальним S3-посиланням на згенероване медіа.
5. Підводні камені, типові помилки та безпека
- Парсинг JSON перед верифікацією підпису:
Якщо перед перевіркою підпису відпрацював стандартний мідлвар
express.json(), серіалізатор може змінити порядок полів, екранування Unicode-символів або форматування чисел, що призведе до невідповідності контрольної суми HMAC та відмовиInvalid Signature. - Синхронне блокування виконання (Webhook Deadlock):
Виконання важких транзакцій або тривалих HTTP-запитів до зовнішніх API всередині обробника вебхука гарантовано призводить до таймауту на стороні провайдера. Повертайте
200 OKмиттєво після валідації підпису та збереження в чергу. - Відсутність валідації часових міток (Replay Attacks): Зловмисник, що перехопив легітимний підписаний вебхук-запит, може надіслати його повторно через годину. Провайдери додають у підпис часову мітку (timestamp). Перевіряйте, щоб різниця між часом запиту та системним годинником сервера не перевищувала допустиме вікно (наприклад, 5 хвилин).
FAQ: Webhooks (Асинхронні вебхуки)
Пов'язані терміни
Telegram Bot API (API ботів Telegram)
Офіційний HTTP-інтерфейс платформи Telegram, що дозволяє створювати автономних чат-ботів, AI-асистентів, інтерфейси Telegram Mini Apps (TMA) та канали інтерактивного сповіщення.
Крон-планувальники (Cron Schedulers & Systemd Timers)
Системні демони (Linux cron, systemd timers) та розподілені черги (BullMQ, Temporal), що забезпечують гарантований запуск періодичних інженерних задач, бекапів, синхронізації даних та AI-агентів за розкладом.
Rate Limiting (Обмеження частоти запитів та захист API)
Системний механізм контролю інтенсивності вхідного та вихідного трафіку (Token Bucket, Sliding Window) для захисту бекенду від вичерпання ресурсів, брутфорсу, Layer 7 DDoS та фінансового овердрафту на AI-ендпоінтах.
Зворотний проксі (Nginx, Caddy, Traefik)
Проміжний серверний архітектурний шар, який приймає зовнішній інтернет-трафік (порти 80/443), виконує термінацію SSL/TLS, стиснення (Brotli/Gzip), кешування статики та безпечно маршрутизує запити до внутрішніх додатків.