Garanzia di spedizione Web Hook
Webhook - Notifiche asincrone dal sistema al sottoscrittore HTTP (S). Rete non affidabile: le risposte vengono perse, i pacchetti vengono duplicati o fuori dall'ordine. Pertanto, le garanzie di spedizione non sono basate su TCP, ma a livello di protocollo Web e idampotenza di dominio.
L'obiettivo chiave è quello di garantire la consegna at-least-once con l'ordine della chiave (ove necessario), fornire al sottoscrittore materiale idipotente e strumento di recupero.
1) Livelli di garanzia
Best-effort è un tentativo usa e getta, senza retrai. È accettabile solo per gli eventi «irrilevanti».
At-least-once (consigliato) - Sono possibili duplicati e out-of-order, ma l'evento verrà consegnato se il sottoscrittore è disponibile entro un termine ragionevole.
Effectively-exactly-once (a livello di effetto) - Viene raggiunto da una combinazione di idampotenza e deposito dedup sul lato sottoscritto/mittente. Il trasporto HTTP «exactly-once» non è possibile.
2) Contratto webhook: minimo necessario
Intestazioni (esempio):
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
Corpo (esempio):
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
}
Il destinatario deve rispondere rapidamente «2xx» dopo il buffering e la convalida della firma e l'elaborazione aziendale è asincrona.
3) Ordine e causalità
Ordine chiave: la garanzia «non partirà» all'interno di un solo «partition _ key» (ad esempio, «player _ id», «wallet _ id», «psp _ tx _ id»).
L'ordine globale non è garantito.
Sul lato del mittente c'è la coda con la serializzazione a chiave (un utente/charding), sul lato del destinatario inbox con' (source, event _ id) 'e in attesa opzionale di «seq» saltati.
Se i pass sono critici, può fornire pull-API'GET/events '? after = checkpoint "per lo stato" inseguimento e controllo ".
4) Idampotenza e deduplicazione
Ogni webhook porta un X-Webhook-ID stabile.
Il destinatario memorizza «inbox (event _ id)»: PK - «source + event _ id»; ripetizioni no-op.
Gli effetti collaterali (scrittura nel database/portafoglio) vengono eseguiti una sola volta alla prima «visione» dell'evento.
Per i comandi Effetto, utilizzare Idempotency-Key e la cache dei risultati durante la finestra dei retrai.
5) Retrai, backoff e finestre
Policy retraes (arbitro):- Ritraccia su '5xx/timeout/connection errore/409-Conflict (retryable )/429'.
- Non ritrarre su «4xx» oltre a «409/423/429» (e solo con una semantica coerente).
- Backoff esponenziale + full jitter: 0. 5s, 1s, 2s, 4s, 8s, … prima dì max = 10-15 min '; TTL finestre retraici, ad esempio 72 ore.
- Rispetta Retry-After dal destinatario.
- Condividi la deadline per dichiarare l'evento non consegnato e tradurlo in 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 - «cimitero» di eventi velenosi o scaduti secondo TTL con metainformazione completa (payload, intestazioni, errori, tentativi, hash).
Web console/API per redrive (reimpostazione a punti) con modifica opzionale endpoint/segreto.
Rate-limited redrive e batch-redrive con priorità.
7) Sicurezza
mTLS (se possibile) o TLS 1. 2+.
Firma corpo (HMAC con il segreto per tenant/endpoint). Verifica:1. Estrai 't' (timestamp) dal titolo, controlla la finestra di scorrimento (ad esempio, © 5 min).
8) Quote, rate limits e giustizia
Fair-Queue per tenant/subscriber: in modo che un utente/tenente non segni un pool condiviso.
Quote e limiti burst per il traffico in uscita e per-endpoint.
Risposta a «429»: onorare «Retry-After», trottolare il flusso; durante la limitazione prolungata - degrade (invio solo di tipi di eventi critici).
9) Ciclo di vita della sottoscrizione
Registrer/Verify: POST endpoint → challenge/response o out-of-band conferma.
Lease (opzionale) - La firma è valida _ to; La proroga è chiara.
Secret rotation: `current_secret`, `next_secret` с `switch_at`.
Test ping è un evento artificiale per verificare il percorso prima di attivare i topic principali.
Provini Health: HEAD/GET periodici con controllo del profilo latency e TLS.
10) Evoluzione degli schemi (versioni degli eventi)
Versioning del tipo di evento: 'payment. authorized. v1` → `…v2`.
Evoluzione - additive (nuovi campi → MINOR API), breaking → un nuovo tipo.
Registro schemi (JSON-Schema/Avro/Protobuf) + convalida automatica prima dell'invio.
Il titolo «X-Event-Type» e il campo «schema _ variante» nel corpo sono entrambi obbligatori.
11) Osservabilità e SLO
Metriche (tipo/tenente/abbonato):- `deliveries_total`, `2xx/4xx/5xx_rate`, `timeout_rate`, `signature_fail_rate`.
- «attemps _ avg», 'p50/p95/p99 _ delivery _ latency _ ms' (da pubblicazione a 2xx).
- `dedup_rate`, `out_of_order_rate`, `dlq_rate`, `redrive_success_rate`.
- `queue_depth`, `oldest_in_queue_ms`, `throttle_events`.
- La percentuale di consegna è di 60 c (p95) a 99. 5% per eventi critici.
- DLQ ≤ 0. 1% in 24 ore.
- Signature failures ≤ 0. 05%.
Логи/трейсинг: `event_id`, `partition_key`, `seq`, `attempt`, `endpoint`, `tenant_id`, `schema_version`, `trace_id`.
12) Algoritmo arbitrale del mittente
1. Registra l'evento in outbox transazionale.
2. Definisci partition _ key e seq; Inserisci nella coda.
3. Worker prende la chiave, crea la richiesta, firma, invia i timeout (connect/read).
4. Con «2xx» - Ammettere la consegna, fissare la latitanza e il seq-checkpoint.
5. Con «429/5xx/timeout» è un retrai secondo la regola.
6. Per TTL, DLQ e alert.
13) Gestore di controllo (destinatario)
1. Accetta richiesta, controlla TLS/proto.
2. Convalida la firma e la finestra del tempo.
3. ACK 2xx veloce (dopo la scrittura sincrona in inbox/coda locale).
4. Il worker asincrono legge inbox, controlla event _ id, se necessario: ordina seq all'interno di partition _ key.
5. Esegue gli effetti, scrive «offset/seq checkpoint» per il reconcile.
6. In caso di errore, retrai locali; Attività «velenose» con DLQ locale con alert.
14) Riavcile (loop di pool)
Per gli incidenti «impraticabili»:- `GET /events? partition _ key =... & after _ seq =... & limit =... '- restituire tutti i mancati.
- Token checkpoint: 'after = opache _ token', invece di seq.
- Redelivery idipotente: stessi «event _ id», stessa firma per la nuova «t».
15) Titoli e codici utili
2xx ha accettato (anche se l'elaborazione aziendale è successiva).
410 Gone - endpoint chiuso (il mittente interrompe la consegna e segna l'abbonamento come «archivio»).
409/423 - Il blocco temporaneo della risorsa è ragionevole.
429 - troppo spesso trottle e backoff.
400/401/403/404 - Errore di configurazione fermare i retrai, aprire il ticchetto.
16) Multi-tenente e regioni
Code separate e limiti per tenant/endpoint.
Data residency: invio da regione dati Titoli completi «X-Tenant», «X-Region».
Isolamento guasto: la caduta di un sottoscritto non influisce sugli altri (separate pools).
17) Test
Contract test - Esempi fissi di corpi/firme, convalida di convalida.
Chaos: drop/duplicati, shuffle ordine, ritardi di rete, «RST», «TLS» - errori.
Load: burst-storm, fermo p95/p99.
Sicurezza: anti-repliche, timestamp obsoleti, segreti sbagliati, rotazione.
DR/Replay: redrive di massa del DLQ in uno stand isolato.
18) Playbooks (runbooks)
1. Altezza dì firma _ fail _ rat'
Controllare la deriva dell'orologio scaduto'tolerance ', rotazione dei segreti; attivare temporaneamente dual secret.
2. La coda invecchia ('oldest _ in _ queue _ ms' ↑)
Aumentare i worker, attivare la priorità dei topic critici, ridurre temporaneamente la frequenza dei tipi «rumorosi».
3. Tempesta «429» dal sottoscritto
Attivare il trottling e le pause tra i tentativi; Spostare i tipi di eventi meno critici.
4. «5xx» di massa
Apri il circuito-breaker per un endpoint specifico, metti in modalità defer & batch; un segnale al sottoscritto.
5. Compilazione DLQ
Interrompere la pubblicazione non critica, attivare batch-redrive con RPS basso, sollevare gli alert ai proprietari delle sottoscrizioni.
19) Errori tipici
Elaborazione sincrona pesante fino alla risposta 2xx retrai e duplicati.
Nessuna firma corpo/finestra del tempo per la vulnerabilità al cambio/replica.
L'assenza dì event _ id «è inbox» non può essere resa idempotica.
Un tentativo di «ordine globale» di bloccare le code per sempre.
Retrai senza jitter/limiti aumentano l'incidente (thundering herd).
Un pool comune su tutti gli abbonati «rumoroso» mette tutti.
20) Foglio di assegno prima della vendita
- Contratto: 'event _ id', 'partition _ key', 'seq', 'event _ type'. vN, firma HMAC e timestamp.
- Mittente: outbox, serializzazione in chiave, retrai con backoff + jitter, TTL, DLQ e redrive.
- Destinatario: scrittura rapida in inbox + 2xx; Elaborazione idonea DLQ locale.
- Sicurezza: TLS, firme, anti-repliche, dual-secret, rotazione.
- Quote/limiti: fair-queue per tenant/endpoint, rispetto «Retry-After».
- Riavcile API e checkpoint; Documentazione per gli abbonati.
- Osservabilità: p95/flussi/errori/DLQ, traccia per «event _ id».
- Versioning degli eventi e politica di evoluzione degli schemi.
- playbook di incidenti e «pulsante» di pausa/scongelamento globale.
Conclusione
I webhoop affidabili sono un protocollo su HTTP, non solo «POST con JSON». Contratto chiaro (ID, chiave d'ordine, firma), idempotenza, retrai con jitter, fila equa e playbook ben regolati trasformano il «caso migliore» in un meccanismo di consegna prevedibile e misurabile. Costruisci at-least-once + ordine in chiave + riavcile e il sistema sopravviverà tranquillamente alla rete, ai picchi di carico e agli errori umani.