Cos'è l'idempotenza e come gestisco i webhook duplicati?

L'idempotenza fa sì che un'operazione ripetuta produca lo stesso effetto di un'unica operazione: gestisci i webhook duplicati senza ripetere il loro lavoro.

Una connessione interrotta può lasciarti nell'incertezza se una richiesta di invio sia riuscita. Un acknowledgment perso può anche far sì che un mittente di webhook consegni un evento che la tua applicazione ha già memorizzato.

Questi errori avvengono in direzioni opposte. Bird può riconoscere una richiesta API ripetuta tramite una chiave che fornisci tu. Il tuo receiver di webhook ha bisogno di un proprio registro degli eventi già accettati.

Come posso riprovare un invio in sicurezza?

Riutilizza lo stesso Idempotency-Key e una richiesta identica per ogni nuovo tentativo. La garanzia è l'accettazione esattamente una volta: i nuovi tentativi corrispondenti entro tre ore devono risolversi in un'unica operazione accettata, anche se ne hai perso la risposta.

Scegli tu la chiave, fino a 255 caratteri, e la mantieni tra i tentativi. Un valore stabile come welcome-user/usr_abc123 può identificare un'operazione di messaggio di benvenuto anche dopo il riavvio del processo.

L'header si applica alle richieste mutanti come POST, PATCH e DELETE. Una richiesta senza chiave viene elaborata senza questa deduplicazione. GET ignora l'header perché leggere la risorsa è già sicuro da ripetere.

Bird restituisce la risposta memorizzata per una richiesta completata corrispondente, inclusi status e body originali. La risposta contiene Idempotency-Replay: true, così puoi identificare quel riutilizzo nei tuoi log.

La guida all'idempotenza documenta un valore predefinito di tre ore per la finestra della risposta completata. Un tentativo dopo la scadenza può essere eseguito come nuova operazione. Non fare affidamento su quella chiave in modo permanente per prevenire invii duplicati.

Gli SDK Bird generano una chiave per una mutazione e la riutilizzano nei propri tentativi interni. Il Bird CLI genera anch'esso una chiave per una richiesta mutante quando è assente. Imposta --idempotency-key esplicitamente quando invocazioni di comandi separate devono condividere la stessa operazione.

Per l'invio SMTP, usa l'header del messaggio X-Bird-Idempotency-Key. Questo permette a un invio riprovato di identificare la stessa operazione.

Cosa succede se riutilizzo una chiave in modo errato?

Bird rifiuta un uso conflittuale della chiave anziché restituire una risposta per un'operazione diversa.

SituazioneRisposta e recupero
Stessa chiave e richiesta, risposta conservataLa risposta memorizzata entro il periodo di conservazione, con Idempotency-Replay: true.
Chiave completata riutilizzata per una richiesta diversa409 con E01005, che indica riutilizzo della chiave di idempotenza. Correggi la chiave prima di riprovare.
Un'altra richiesta con quella chiave è ancora in esecuzione409 con E01004, che indica richiesta in corso. Attendi brevemente e riprova.
La chiave supera i 255 caratteri422 con E01001 sugli endpoint che dichiarano l'header. Accorcia la chiave.

Il confronto include metodo, endpoint, parametri del percorso, query string e body. Per JSON, modificare gli spazi cambia l'identità della richiesta, quindi preserva il body originale durante i tentativi.

Se la richiesta originale è ancora in esecuzione, attendi prima di riprovare. Mantieni la stessa chiave e la stessa richiesta, così il nuovo tentativo identifica l'operazione originale.

API non conserva una risposta 5xx come risposta completata. Riprova un timeout o un errore del server con un backoff limitato, la stessa chiave e una richiesta identica entro tre ore. La garanzia di accettazione esattamente una volta copre anche una risposta persa.

Un rifiuto 4xx può essere conservato. Usa una nuova chiave per una richiesta corretta: un nuovo tentativo invariato riproduce il rifiuto conservato, mentre un input modificato entra in conflitto con quella chiave conservata.

Perché ricevo lo stesso webhook due volte?

Bird può riprovare un evento che il tuo receiver ha già memorizzato se non riceve una risposta positiva.

Un receiver può memorizzare un evento subito prima che la sua connessione si interrompa. Bird non vede alcun acknowledgment positivo e riprova, anche se il receiver ha già l'evento.

Ogni nuovo tentativo mantiene lo stesso header webhook-id, che identifica l'evento. Anche un replay di una consegna fallita mantiene quell'identificatore, quindi puoi riconoscere entrambi come lo stesso evento anziché riprovare il lavoro.

Come rendo il mio handler idempotente?

Memorizza ogni webhook-id sotto un vincolo di unicità del database prima di schedulare il lavoro dell'evento.

Verificare l'esistenza di una riga prima di inserirla lascia una race condition: due richieste concorrenti possono entrambe non trovare alcuna riga. Lascia che sia il database a rifiutare gli identificatori duplicati.

Memorizza l'identificatore e il job nella stessa transazione. Questo impedisce che un identificatore venga registrato senza alcun lavoro accodato.

  1. Verifica la richiesta, poi inserisci il suo identificatore e il job nella stessa transazione.
  2. Restituisci 2xx dopo il commit della transazione, così Bird può smettere di riprovare.
  3. Elabora il job memorizzato in un worker che può ripetere in sicurezza le proprie azioni.

Per un identificatore duplicato già committato, restituisci successo senza creare un altro job. Per una transazione fallita, restituisci un errore così Bird riprova.

Tieni il lavoro lento fuori dal receiver perché attenderlo può causare il timeout della richiesta. Un worker può riprovare per motivi non legati alla consegna del webhook, quindi proteggere solo il receiver non è sufficiente.

Gli eventi possono anche arrivare in ordine diverso. Confronta i tempi degli eventi in timestamp prima di sovrascrivere uno stato più recente. Tentativi di webhook falliti include l'esempio del costo parziale.

Su cosa non dovrei fare affidamento?

Non dare per scontato che la deduplicazione delle richieste renda impossibili gli effetti collaterali duplicati.

Per una scrittura HTTP supportata, Bird lega la chiave di idempotenza allo spazio di lavoro o all'organizzazione della richiesta. Le operazioni dello staff supportate usano invece l'account staff che agisce. Se la protezione non è disponibile, Bird restituisce 503 E01033 IdempotencyUnavailable prima di eseguire quel tentativo. Questo non chiarisce l'esito di un tentativo precedente. La garanzia di accettazione exactly-once copre i nuovi tentativi corrispondenti entro tre ore. Controlla lo stato del messaggio per confermare la consegna. Se i nuovi tentativi sono esauriti o la finestra scade, controlla l'esito dell'operazione originale prima di inviare di nuovo.

Analogamente, webhook-id distingue le consegne ripetute di uno stesso evento. Eventi separati hanno identificatori separati. La tua applicazione decide comunque se quegli eventi giustificano la ripetizione della stessa azione.

Idempotenza documenta come riprovare le richieste a API. Webhook copre le garanzie di consegna separate che il tuo receiver gestisce.

In breve

  1. I tentativi verso API e i tentativi webhook richiedono record diversi.

    Riutilizza Idempotency-Key per una richiesta a Bird. Il tuo receiver memorizza webhook-id per riconoscere un evento già accettato.

  2. Anche i rifiuti possono essere conservati.

    Un rifiuto conservato viene riprodotto. Una richiesta corretta richiede una nuova chiave perché il suo input è diverso.

  3. Una chiave completata non può identificare richieste diverse.

    Un body o un endpoint JSON modificato può produrre un conflitto 409. Correggi la chiave anziché riprovare lo stesso conflitto invariato.

  4. La deduplicazione ha dei limiti.

    La garanzia di API copre l'accettazione esattamente una volta dei nuovi tentativi corrispondenti entro tre ore. Il tuo receiver di webhook ha bisogno di propri record persistenti degli eventi.

Costruisci sulla stessa rete.

Una chiave API di test è subito tua. L'accesso alla produzione si sblocca quando aggiungi un metodo di pagamento e verifichi un mittente.

Start building with Bird in minutes.