Se una chiamata a un Durable Object terminava con un errore di rete, spesso spettava allo sviluppatore decidere se inviarla di nuovo. Dal 5 novembre 2026, il runtime di Cloudflare gestisce alcuni di questi tentativi: riprova automaticamente determinate chiamate fetch() e RPC effettuate tramite uno stub. Per il codice applicativo, la domanda centrale ora è più precisa: è sicuro eseguire una seconda volta un determinato metodo?
La risposta dipende dal punto in cui si è interrotta la comunicazione. Il runtime riprova automaticamente alcune chiamate, mantenendo attiva per impostazione predefinita la protezione contro l’esecuzione doppia. In caso di consegna dall’esito incerto, usa lo stesso ID della richiesta e l’oggetto rifiuta il nuovo tentativo se ha già ricevuto quello iniziale. Un metodo contrassegnato esplicitamente con retryable() si comporta diversamente: può essere eseguito di nuovo anche se il primo tentativo è già arrivato all’oggetto. Perciò l’indicazione è adatta solo alle operazioni la cui ripetizione è sicura sia per lo stato sia per gli effetti collaterali.
Che cosa riprova esattamente il runtime
Secondo l’annuncio di Cloudflare del 5 novembre, i tentativi riguardano le chiamate fetch() e RPC a un Durable Object effettuate da un Worker o da un altro Durable Object. Per le chiamate tramite stub sono previsti, per impostazione predefinita, il primo tentativo e fino a quattro ripetizioni; non vengono avviati nuovi tentativi oltre 10 secondi dall’inizio della chiamata.

La condizione è un errore contrassegnato come .retryable. Per esempio, la richiesta potrebbe non aver raggiunto l’oggetto perché era in fase di riavvio o spostamento. Il runtime può riprovare anche se la connessione si interrompe e non è possibile stabilire se l’oggetto abbia ricevuto la richiesta. Se l’oggetto l’ha già ricevuta, il tentativo successivo con lo stesso ID viene rifiutato. Il runtime non riprova gli errori generati dal codice del Durable Object, quelli contrassegnati come .overloaded né le risposte HTTP come 500: si tratta di una risposta del gestore, non di un errore di consegna.
Perché ritentare la consegna non equivale a ripetere l’operazione
Ritrasmettere una richiesta non significa di per sé eseguire il metodo una seconda volta. Se l’esito è incerto, il runtime invia la richiesta con lo stesso ID; se l’oggetto ha ricevuto il tentativo iniziale, rifiuta quello successivo. In modalità normale, questo impedisce che un singolo errore di rete provochi una seconda esecuzione del metodo, per esempio un nuovo addebito o la creazione di un altro record.

Il confine cambia quando il metodo viene contrassegnato con retryable() da cloudflare:durable-objects. In questo caso l’oggetto può rieseguire il metodo anche se il primo tentativo potrebbe essere già iniziato. Cloudflare propone due esempi: assegnare a un prodotto una quantità specifica è idempotente; incrementare la quantità di un’unità non lo è. Ripetere la prima azione imposta lo stesso valore, mentre ripetere la seconda aggiunge un’altra unità.
Occorre controllare non solo lo stato finale dello storage, ma anche tutti gli effetti del metodo. Se un nuovo tentativo genera un altro pagamento, invia un messaggio o avvia un’azione esterna, mantenere lo stesso stato all’interno del Durable Object non rende sicura la ripetizione. L’indicazione è adatta quando ripetere l’operazione non cambia il risultato e non duplica gli effetti collaterali.
Dove è utile dichiarare esplicitamente l’idempotenza
Impostare un valore, registrare un’istantanea dello stato o aggiornare un campo a un valore noto spesso produce lo stesso risultato anche se l’operazione viene ripetuta. Per questi metodi, retryable() può consentire alla chiamata di concludersi con successo dopo un’interruzione della connessione avvenuta mentre l’elaborazione era già iniziata.
Le operazioni «aggiungi», «creane un altro», «addebita» e «invia» di solito richiedono protezioni diverse. Prima di consentire una nuova esecuzione, assicurati che l’operazione applicativa riconosca i duplicati o sia progettata in modo che la ripetizione non produca un secondo effetto. Il nome della funzione non offre garanzie: controlla tutte le modifiche di stato e le azioni esterne eseguite dal metodo.
retryable() ha un ruolo circoscritto: consente di ripetere l’esecuzione quando non è possibile stabilire se la prima chiamata sia arrivata. Non cambia gli errori a cui reagisce il runtime e non aumenta il numero di tentativi. L’indicazione riguarda la funzione; una versione sovrascritta o avvolta del metodo non la eredita automaticamente, a meno che non venga contrassegnata esplicitamente a sua volta.
Che cosa controllare nei progetti già in produzione
Il punto più probabile da rivedere sono i cicli di ripetizione personalizzati che circondano le chiamate ai Durable Objects. Ora ogni tentativo può includere quelli del runtime, quindi il numero complessivo di chiamate può superare quello impostato dalla sola applicazione. Cloudflare consiglia di ridurre il numero di tentativi personalizzati oppure di impostare maxRetries: 0 per lo stub, se i tentativi sono gestiti dal proprio codice.
Per uno stub specifico, i limiti si impostano quando si chiama get() o getByName(). Il parametro maxRetries stabilisce da zero a dieci tentativi oltre a quello iniziale; timeoutMs definisce l’intervallo oltre il quale non vengono avviati altri tentativi, da 500 a 60.000 millisecondi. Queste impostazioni si applicano alle chiamate effettuate tramite quello stub. Per usare retryable() e l’oggetto retry è necessario Wrangler 4.158.0 o versione successiva.
Una revisione utile consiste nel porsi tre domande per ogni chiamata: può modificare lo stato più di una volta? Può ripetere effetti collaterali esterni? L’applicazione applica una propria politica di tentativi? Poi si può decidere se lo stub deve usare i valori predefiniti o limiti personalizzati. Per i metodi idempotenti, si può valutare separatamente l’indicazione esplicita; per gli altri, è meglio mantenere la protezione e verificare come viene gestito l’errore quando l’esito del primo tentativo è sconosciuto.
Conseguenza: la responsabilità si sposta al confine del metodo
I tentativi automatici eliminano parte della logica di rete dal codice applicativo, ma la decisione sulla sicurezza di una nuova esecuzione resta una proprietà dell’operazione. Il runtime può ritrasmettere la richiesta in sicurezza e fermarsi se non sa se la chiamata sia stata eseguita. Lo sviluppatore può autorizzare una nuova esecuzione del metodo, confermando esplicitamente che non duplica modifiche di stato o effetti collaterali.
Perciò l’aggiornamento va interpretato come una modifica del contratto tra il livello di trasporto e il gestore. Per prima cosa, controlla i cicli di tentativi personalizzati e la ripetibilità degli effetti collaterali; poi configura i limiti sugli stub interessati. In questo modo la resilienza integrata ai guasti temporanei si combina con il controllo sulle operazioni per cui una seconda esecuzione ha un costo reale.