Webhooks ve etkinlik idempotency
TL; DR
İyi bir webhook imzalı (HMAC/mTLS), alıcıda üstel yedekleme ve veri tekilleştirme ile en az bir kez modelde sunulan özetlenmiş ve idempotent bir olaydır. Bir zarf ('event _ id', 'type', 'ts', 'version', 'trease', 'signature'), zaman penceresi (≤5 dakika), yanıt kodları, retrays, DLQ ve durum uç noktası üzerinde anlaşın.
1) Roller ve teslimat modeli
Gönderen (siz/sağlayıcı): bir olay oluşturur, imzalar, 2xx'e kadar teslim etmeye çalışır, 3xx/4xx/5xx'de retrait (açık'kabul etmeyin "hariç), DLQ'yu yönlendirir, tekrar API verir.
Alıcı (ortak/hizmetiniz): imza/zaman penceresini kontrol eder, dedup ve idempotent işleme yapar, doğru kodla yanıt verir ,/status ve/ack replay by 'event _ id' sağlar.
Garantiler: en az bir kez. Alıcı, kopyaları ve yeniden sıralamayı işleyebilmelidir.
2) Olayın zarfı
json
{
"event_id": "01HF7H9J9Q3E7DYT5Y6K3ZFD6M",
"type": "payout.processed",
"version": "2025-01-01",
"ts": "2025-11-03T12:34:56.789Z",
"attempt": 1,
"producer": "payments",
"tenant": "acme",
"data": {
"payout_id": "p_123",
"status": "processed",
"amount_minor": 10000,
"currency": "EUR"
}
}
Gerekli alanlar 'event _ id', 'type', 'version', 'ts', 'trease'dir.
Evrim kuralları: alanları ekleyin; Türleri sil/değiştir - yalnızca yeni 'sürüm'ile.
3) Güvenlik: imzalar ve bağlayıcı
3. 1 HMAC imzası (varsayılan olarak önerilir)
Başlıklar:
X-Signature: v1=base64(hmac_sha256(<secret>, <canonical>))
X-Timestamp: 2025-11-03T12:34:56Z
X-Event-Id: 01HF7...
Kanonik dize:
<timestamp>\n<method>\n<path>\n<sha256(body)>
Alıcıya danışın:
- abs (şimdi − 'X-Timestamp') ≤ 300'ler
- Daha önce işlenmeyen 'X-Event-Id' (dedup)
- 'X-İmza' eşleşmeleri (zaman açısından güvenli karşılaştırma)
3. 2 Add. Önlemler
Son derece hassas webhook'lar için mTLS.
IP/ASN izin listesi.
DPoP (isteğe bağlı), webhook geri çağırmaları başlatırsa gönderici kısıtlamalı için.
4) Idempotency ve veri tekilleştirme
4. 1 Olay idempotency
'Event _ id'ile aynı olan bir olay durumu tekrar değiştirmemelidir. Alıcı:- 'event _ id' 24-72 saat ≥ TTL'de idempotent önbelleğinde (KV/Redis/DB) saklanır;
- Yeniden dönüş için işlem sonucunu (başarı/hata, artifaktlar) kaydeder.
4. 2 Komut idempotency (geri çağırma)
Webhook, istemciyi API'yi çekmeye zorlarsa (örneğin, "ödemeyi onayla"), REST çağrısında 'Idempotency-Key' kullanın, sonucu servis tarafında saklayın (tam olarak bir kez sonuç).
KV modeli (minimum):
key: idempotency:event:01HF7...
val: { status: "ok", processed_at: "...", handler_version: "..." }
TTL: 3d
5) Retrai ve geri alma
Önerilen arsa (jitter ile üstel):- '5s, 15s, 30s, 1m, 2m, 5m, 10m, 30m, 1h, 3h, 6h, 12h, 24h' (daha sonra N güne kadar günlük)
- 2xx - başarı, retrays durdurmak.
- '400/ 401/403/404/422' - imza/format tamam ise (istemci hatası) geri çekilemez.
- '429' - 'Retry-After'or backoff tarafından retrayim.
- 5xx/network - retrayim.
Gönderici başlıkları: 'Kullanıcı-Aracı', 'X-Webhook-Producer', 'X-Girişimi'.
6) Alıcı tarafı işleme
Sözde boru hattı:pseudo verify_signature()
if abs(now - X-Timestamp) > 300s: return 401
if seen(event_id):
return 200 // идемпотентный ответ
begin transaction if seen(event_id): commit; return 200 handle(data) // доменная логика mark_seen(event_id) // запись в KV/DB commit return 200
İşlemsellik: "Görülen" etiketi, arızada çift işlemden kaçınmak için işlemin etkisiyle (veya sonucu sabitledikten sonra) atomik olarak ayarlanmalıdır.
7) Sipariş ve anlık görüntü garantileri
Sipariş garanti edilmez. Alaka düzeyini doğrulamak için 'data'da' ts've domain 'seq'/' version' kullanın.
Uzun gecikmeler/kayıplar için - göndericide ekleme/tekrar oynatma ve alıcıda/resync (zaman/kimlik penceresinde anlık görüntü ve deltalar alın).
8) Durum, tekrar oynatma ve DLQ
8. 1 Gönderici uç noktaları
'POST/webhooks/replay' - 'event _ id' listesine veya zaman penceresine göre.
'GET/webhooks/events/: id' - kaynak paketi ve girişimlerin geçmişini gösterir.
DLQ: "Ölü" olaylar (geri ödeme sınırı tükendi) - ayrı depolama, uyarılar.
8. 2 Alıcı uç noktaları
'GET/ webhooks/status/:event_id' -' seen = true/false ',' processed _ at ',' handler _ version '.
'POST/webhooks/ack' - (isteğe bağlı) DLQ'dan manuel işleme onayı.
9) Hata sözleşmeleri (alıcı yanıtı)
http
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json
Retry-After: 120
X-Trace-Id: 4e3f...
{
"error": "invalid_state",
"error_description": "payout not found",
"trace_id": "4e3f..."
}
Öneriler: her zaman açık bir kod ve mümkünse 'Retry-After' döndürün. Ayrıntılı güvenlik ayrıntılarını iade etmeyin.
10) İzleme ve SLO
Metrikler (gönderen):- Teslimat p50/p95, başarı oranı, retray/event, drop-rate DLQ, share 2xx/4xx/5xx, 2xx'e kadar gecikme penceresi.
- Hata oranını doğrulayın (imza/zaman), dup-rate, latency handler p95, 5xx.
- Teslimat: 99 ≥. Olayların %9'u 2xx <3 c p95 (ilk başarılı denemeden sonra) alır.
- Kriptografik doğrulama: imza doğrulama ≤ 2-5 ms p95.
- Dedup: 0 tekrarlanan etkiler (etki alanı düzeyinde tam olarak bir kez sonuç).
11) Veri güvenliği ve gizliliği
PAN/PII'yi webhook'un gövdesine iletmeyin; Kimlikleri kullanın ve ardından yetkili bir API'ye karşı ayrıntılar için çekin.
Günlüklerdeki hassas alanları maskeler; Etkinlik organlarını TTL ile minimum düzeyde saklayın.
DLQ depolarını şifreleyin ve yeniden oynatın.
12) Sürüm oluşturma ve uyumluluk
Sürüm içinde 'sürüm' (zarf) ve transit:'/webhooks/v1/payments '.
Yeni alanlar isteğe bağlıdır; Kaldırma - sadece 'Sunset' döneminden sonra.
Makine tarafından okunabilir değişiklik listesindeki değişiklikleri belgeleyin (otomatik kontroller için).
13) Test durumları (UAT kontrol listesi)
- Kopyalara aynı 'event _ id' - bir efekt ve '200' yeniden verilmesi.
- İmza: doğru anahtar, yanlış anahtar, eski anahtar (döndürme), 'X-Timestamp' pencerenin dışında.
- Backoff: Alıcı, 'Retry-After'ile' 429 'verir - doğru duraklama.
- Sipariş: Olaylar '... İşlenmiş'daha önce gel '... yaratıldı '- doğru işleme/bekleme.
- Etki ve 'mark _ seen' arasında alıcıda veritabanı hatası - atomicity/repeat.
- DLQ ve manuel yeniden oynatma - başarılı teslimat.
- Kitle "fırtına" (sağlayıcı paketleri gönderir) - kayıp olmadan, limitler kritik boğmak yok.
14) Mini snippet'ler
Gönderen imzası (sözde):pseudo body = json(event)
canonical = ts + "\n" + "POST" + "\n" + path + "\n" + sha256(body)
sig = base64(hmac_sha256(secret, canonical))
headers = {"X-Timestamp": ts, "X-Event-Id": event.event_id, "X-Signature": "v1="+sig}
POST(url, body, headers)
Kontrol ve hedef (sözde):
pseudo assert abs(now - X-Timestamp) <= 300 assert timingSafeEqual(hmac(secret, canonical), sig)
if kv.exists("idemp:"+event_id): return 200
begin tx if kv.exists("idemp:"+event_id): commit; return 200 handle(event.data) // доменная логика kv.set("idemp:"+event_id, "ok", ttl=259200)
commit return 200
15) Sık yapılan hatalar
Veri tekilleştirme yok - tekrarlanan etkiler (çift geri ödeme/ödemeler).
Zaman damgası/pencere olmadan imza - yeniden oynatma güvenlik açığı.
Bir HMAC sırrını tüm ortaklara saklamak.
Sonucu düzeltmeden önce '200' yanıtları - çarpışma olaylarının kaybı.
Güvenlik ayrıntılarını yanıtlara/günlüklere "yıkama".
DLQ/tekrarlama eksikliği - olaylar çözülemez.
16) Uygulama hile sayfası
Güvenlik: HMAC v1 + 'X-Timestamp' + 'X-Event-Id', pencere ≤ 5 dakika; Gerektiği gibi mTLS/IP allow-list.
Конверт: 'event _ id', 'type', 'version', 'ts', 'trake', 'data'.
Teslimat: En az bir kez, jitter, 'Retry-After', DLQ + replay API ile geri çekilme.
Idempotency: KV-cache 24-72 h, etkinin atomik fiksasyonu + 'mark _ seen'.
Gözlemlenebilirlik: teslimat, imza, yinelenen metrikler; trace _ id.
Dokümantasyon: sürüm, yanıt kodları, örnekler, UAT kontrol listesi.
Özgeçmiş Özeti
Kalıcı webhooks üç balina üzerine inşa edilmiştir: imzalı bir zarf, en az bir kez teslimat ve idempotent işleme. Sözleşmeyi resmileştirin, HMAC/mTLS ve zaman penceresini etkinleştirin, retrai + DLQ'yu uygulayın ve tekrar oynatın, idempotent etiketleri saklayın ve efektleri atomik olarak yakalayın. Daha sonra olaylar ağ arızaları, yük zirveleri ve nadir "kaderin kopyaları'ile bile güvenilir kalır.