GH GambleHub

Strategie di ripetizione e idipotenza

1) Perché è necessario

Le reti di guasti sono la norma: timeout, transit, flapping di rete, sovraccarico. I retrai migliorano l'affidabilità solo se:

1. il ripetizione è sicuro (idipotente),

2. vengono rispettate le estensioni tra le ricorrenze,

3. sono rispettati i limiti/quote e la «salute» delle dipendenze.

L'obiettivo è un comportamento effettively-once a livello di business senza false riprese e corse.

2) Tassonomia semantica di consegna

At-not-once: senza ripetizione, rischio di perdita (logica, fire-and-forget).
At-least-once - È possibile duplicare il → richiede l'idipotenza del consumatore (la maggior parte delle code, webhoop).
Effectively-once: i duplicati sono possibili ma deduplicati correttamente (chiavi, transazioni, outbox).

3) Quando ritrarre e quando no

La retrazione ha senso: «408», «429» (rispettando «Retry-After»), «425» (Too Early), «499» (client closed sul perimetro), «5xx», «504», timeout di rete, «502» sul gateway, «connection reset».
Non ritraiamo senza modificare la richiesta «400/ 401/403/404/422».
Valigette controverse: '409 Conflict' (di solito non retraiamo; Prima leggiamo lo stato dell'operazione/ricalcoliamo l'intenzione).

4) Timeout, backoff e jitter

4. 1 Regole

Prima il timeout, poi i ritrasmi, ogni richiesta deve avere deadline.
Exponential backoff: «delay _ n = base 2 ^ n», limitiamo «max _ delay».
Jitter è obbligatorio: aggiungi casualità alla fine delle onde sincroni stupide.

4. 2 Modelli di jitter

Full jitter: 'sleep = rand (0, base2 ^ n)' è la scelta condivisa migliore.
Decorated jitter: 'sleep = min (max _ delay, rand (base, sleep _ prev3))' - per interazioni lunghe.
Equal jitter: 'sleep = base2 ^ n/2 + rand (0, base2 ^ n/2)' è una variazione morbida.

4. 3 Retry-budget

Limitate la quota di retrai:
  • `retry_budget_per_min = max(α success_rps, floor β)`; Solitamente, '© = 0. 1–0. 2`.
  • Quando il budget è esaurito, passiamo a fail-fast/circuito breaker «open».

5) Interazione con rate limiting e Circuito Breaker

Rispettate Retry-After, RateLimit-Reset e consideratelo un back-off.
Con gli alti «5xx »/timeout - ridurre la frequenza dei retrai e il parallelismo generale.

Circuit breaker:
  • Half-open: consente un campione limitato.
  • Open: rifiuta istantaneamente (risparmia la risorsa).
  • Closed è un lavoro normale.
  • Nelle operazioni write è preferibile restituire 409/503 con un suggerimento chiaro piuttosto che girare i retrai aggressivi.

6) Idampotenza delle operazioni write

6. 1 Idea generale

Le stesse intenzioni → un solo risultato. La base è la chiave di idempotenza e l'archivio delle registrazioni di esecuzione.

6. 2 contratto HTTP

Il cliente invia il titolo:

Idempotency-Key: 7a6b7f9e-2a46-4d0b-9c3a-2b30e1c3c9e3
Idempotency-Key-Expiry: 24h # optional
Server:
  • Al primo successo, salva (chiave, risultato, stato, hash del corpo).
  • Quando viene ripetuta, restituisce la risposta precedente e il titolo «Idempotency-Replay: true»;
  • quando il corpo è in conflitto (stessa chiave, ma altra payload) - '409 Conflict'.

6. 3 Storage e TTL

Tabella/chiave-valore: «idempotency _ key», «sollest _ hash», «result», «status», «expiry _ at».
TTL = una finestra di possibili ripetizioni e consegne tardive (generalmente 24-72 ore per i pagamenti).
Indici dì idempotency _ key "; per l'alto carico di lavoro, charding su hashtag.

6. 4 Schema di esempio (SQL)

sql
CREATE TABLE idempo_store (
key UUID PRIMARY KEY,
req_hash BYTEA NOT NULL,
status INT NOT NULL,
response JSONB NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
expiry_at TIMESTAMPTZ NOT NULL
);

6. 5 Pseudocode processore

pseudo handle_write(req):
k = req. headers["Idempotency-Key"]
h = hash(req. body)
rec = idempo_store. get(k)

if rec and rec. req_hash == h:
return rec. status, rec. response, {"Idempotency-Replay": "true"}

if rec and rec. req_hash!= h:
return 409, problem("IDEMPOTENT_CONFLICT")

begin tx result = apply_business_mutation (req) # change status upsert once (idempo_store, key = k, req_hash=h, status = 201, response = result, expiry = now () + 2d)
commit

return 201, result

7) Pattern «effectively-once»

Transactional Outbox: registrazione dell'evento aziendale e invio di un messaggio dalla stessa transazione database tramite relayer di sfondo il consumatore è idoneo.
Inbox/Processed-Table del consumatore: salviamo «event _ id» per ignorare le riprese.
Exactly-once su Kafka per exactly-once nel business: anche con EOS produttore/concertatore, la logica applicativa deve essere comunque idemotante.
Transazioni compensative (Saga) - Se i passi vengono ritracciati e causano effetti collaterali, restituiamo il sistema all'invariante.

8) Casi privati: pagamenti e transazioni finanziarie

Strong idempotency - La chiave è collegata alla logica dell'operazione (ad esempio, 'external _ payment _ id').
La deduplicazione su PSP memorizza'merchant _ reference ', che restituisce il risultato precedente.
Retrai «da cliente»: autorizza solo con «Idempotency-Key», altrimenti il rischio di doppia cancellazione.
Concorrenza: blocchi su account/strumento/contratto per il periodo di esecuzione; se ripetuto, restituisci 409/423.
Osservabilità: metriche «idempo _ replay _ total», «idempo _ conflict _ total».

9) Webhook e chiamate esterne

Firme HMAC e finestra temporale Prima il controllo, poi l'elaborazione.
Retrai del mittente: backoff esponenziale + jitter, "max _ attemps'e DLQ.
Il consumatore è idepotente: 'event _ id', tabella/in-memory cache; l'ordine «attento» non è garantito.
Codici: 2xx = riuscito, 4xx = non ripetere, 5xx/timeout = ripetere.

10) Code e attività di sfondo

At-least-once predefinito duplicati sono inevitabili.
Memorizza «task _ id »/« event _ id» e lo stato di esecuzione; durante la ripresa, un breve percorso «replay».
DLQ e poison-messaggistica: conteggio tentativi, quarantena, analisi manuale.
Limiti competitivi (semafori) e worker idempotenti.

11) Versioning e chiavi «naturali»

Le chiavi naturali (numero di conto + data + numero di documento) aumentano la resistenza alle ricorrenze.
Quando cambi schema/versione, inserisci la chiave di versione in Idempotency-Key o nell'hash della query.

12) Intestazioni HTTP e suggerimenti al client

«Idempotency-Key», «Idempotency-Replay», «Retry-After», «Preferer: wait = <sec>», «If-Match »/« ETag» (blocchi ottimistici).
409 in caso di conflitto di chiavi, 425/429/503 con il valico «Retry-After».
Per le operazioni «lunghe», accetta lo stato asincrono ('202 Accetted' + Location ', per risorsa di stato).

13) Test e script di caos

Test negativi: doppio invio, ripetizione con altro corpo, rassincrone ore.
"t2" arriva prima dì t1 ".
Iniezione di timeout/« RST »/« EOF », richieste a metà (slow-POST).
Un deposito idempotency decaduto → il comportamento fail-closed (meglio un guasto che una doppia cancellazione).

14) Metriche e alerti

`retries_total{reason}`, `retry_budget_used{route}`, `backoff_seconds_bucket`.
`idempo_replay_total`, `idempo_conflict_total`, `duplicate_detected_total`.
Quota 409/425/429/5xx lungo le rotte; p95/p99 «tempo prima del successo» con i retrai.
Alert: bilancio burn-rate dei retrai, aumento dei conflitti di idempotenza, crescita del DLQ.

15) Antipattern

Ritrattare tutti gli errori di fila.
L'assenza di un jitter ha → le onde sincronizzate dei retrai.
Chiavi a lunga vita senza TTL e pulizia.
Salva il risultato dopo l'effetto collaterale (violazione outbox).
I loghi senza «trace _ id »/« idempotency _ key» non possono essere forensi.
Retrai paralleli aggressivi su operazioni write.

16) Assegno-foglio prod-pronto

  • Politica unificata: cosa ritraiamo, cosa no; codici e suggerimenti al cliente.
  • Backoff esponenziale + full jitter; impostato'retry _ budget get '.
  • Contratto «Idempotency-Key» + Memorizzazione risultati con TTL.
  • Outbox/Inbox per gli eventi; DLQ; limiti di competitività.
  • Integrazione con il circuito breaker, respect 'Retry-After'.
  • Metriche/alert per retrai/duplicati/conflitti.
  • Serie di test di caos e emulazione di guasti di rete.
  • Documentazione per i clienti: esempi di back-off e di stato.

17) TL; DR

I retrai sono utili solo con l'idipotenza. Immettere «Idempotency-Key» e l'archivio risultati, applicare backoff esponenziale con jitter e retry-budget, rispettare «Retry-After», integrarsi con il circuito breaker. Per gli eventi - outbox/inbox; per i pagamenti: deduplicazione e blocchi rigorosi. Misurare retrai e conflitti, testare duplicati e timeout.

Contact

Mettiti in contatto

Scrivici per qualsiasi domanda o richiesta di supporto.Siamo sempre pronti ad aiutarti!

Telegram
@Gamble_GC
Avvia integrazione

L’Email è obbligatoria. Telegram o WhatsApp — opzionali.

Il tuo nome opzionale
Email opzionale
Oggetto opzionale
Messaggio opzionale
Telegram opzionale
@
Se indichi Telegram — ti risponderemo anche lì, oltre che via Email.
WhatsApp opzionale
Formato: +prefisso internazionale e numero (ad es. +39XXXXXXXXX).

Cliccando sul pulsante, acconsenti al trattamento dei dati.