Questo documento descrive come richiedere il nuovo tentativo di esecuzione delle funzioni asincrone (non HTTPS) in background in caso di errore.
Perché le funzioni basate su eventi non vengono completate
In rare occasioni, una funzione potrebbe terminare prematuramente a causa di un errore interno e, per impostazione predefinita, il tentativo di esecuzione della funzione potrebbe essere ripetuto o meno automaticamente.
In genere, una funzione basata su eventi potrebbe non essere completata correttamente a causa di errori generati nel codice della funzione stesso. I motivi per cui ciò potrebbe accadere includono:
- La funzione contiene un bug e il runtime genera un'eccezione.
- La funzione non riesce a raggiungere un endpoint di servizio o si verifica un timeout durante il tentativo di farlo.
- La funzione genera intenzionalmente un'eccezione (ad esempio, quando la convalida di un parametro non va a buon fine).
- Una funzione Node.js restituisce una promessa rifiutata o passa un valore non
null
a un callback.
In uno qualsiasi dei casi precedenti, la funzione interromperà l'esecuzione e restituirà un errore. I trigger di eventi che producono i messaggi hanno criteri di ripetizione che puoi personalizzare per soddisfare le esigenze della tua funzione.
Semantica del nuovo tentativo
Cloud Functions fornisce l'esecuzione almeno una volta di una funzione basata su eventi per ogni evento emesso da un'origine eventi. Il modo in cui configuri i tentativi dipende da come hai creato la funzione:
- Le funzioni create nella console Google Cloud o con l'Cloud RunAPI Admin richiedono la creazione e la gestione separata dei trigger di eventi. I trigger hanno comportamenti di ripetizione predefiniti che puoi personalizzare in base alle esigenze della tua funzione.
- Le funzioni create con l'API Cloud Functions v2 creeranno implicitamente i trigger di eventi necessari, ad esempio argomenti Pub/Sub o trigger Eventarc. Per impostazione predefinita, i tentativi vengono disattivati per questi trigger e possono essere riattivati utilizzando l'API Cloud Functions v2.
Funzioni basate su eventi create con Cloud Run
Le funzioni create nella console Google Cloud o con l'API Admin richiedono la creazione e la gestione separate dei trigger di eventi.Cloud Run Ti consigliamo vivamente di esaminare il comportamento predefinito di ogni tipo di trigger:
- Il Eventarc criterio di ripetizione ha un periodo di conservazione dei messaggi predefinito di 24 ore con un ritardo di backoff esponenziale. Consulta la documentazione di Eventarc sugli eventi di ripetizione.
- Pub/Sub per impostazione predefinita utilizza la policy di riconsegna immediata per tutti gli abbonamenti. Consulta la documentazione di Pub/Sub su gestione degli errori dei messaggi e richieste di nuovi tentativi.
Funzioni basate sugli eventi create con l'API Cloud Functions v2
Le funzioni create utilizzando l'API Cloud Functions v2, ad esempio utilizzando gcloud CLI Cloud Functions, l'API REST o Terraform, creeranno e gestiranno i trigger di eventi per tuo conto. Per impostazione predefinita, se una chiamata di funzione termina con un errore, la funzione non viene richiamata di nuovo e l'evento viene eliminato. Quando abiliti i tentativi sulla funzione basata su eventi, Cloud Functions riprova a richiamare una funzione non riuscita finché non viene completata correttamente o finché non scade la finestra di tentativi.
Quando i tentativi non sono attivati per una funzione, ovvero l'impostazione predefinita, la funzione
segnala sempre che è stata eseguita correttamente e nei log potrebbero
essere visualizzati codici di risposta 200 OK
. Ciò si verifica anche se la funzione ha riscontrato un errore. Per
rendere chiaro quando la funzione rileva un errore, assicurati di
segnalare gli errori
in modo appropriato.
Attivare o disattivare i tentativi
Configura i tentativi dal codice della funzione
Con Cloud Functions for Firebase, puoi attivare i tentativi nel codice per una funzione. Per farlo per una funzione in background come
functions.foo.onBar(myHandler);
, utilizza
runWith
e configura una policy di errore:
functions.runWith({failurePolicy: true}).foo.onBar(myHandler);
L'impostazione di true
come mostrato configura una funzione per riprovare in caso di errore.
Finestra di tentativi
Per le funzioni di 2ª gen., questa finestra di nuovi tentativi scade dopo 24 ore. Per le funzioni di 1ª gen., scade dopo 7 giorni. Cloud Functions esegue nuovamente i tentativi per le funzioni basate su eventi appena create utilizzando una strategia di backoff esponenziale, con un backoff crescente compreso tra 10 e 600 secondi. Queste norme vengono applicate alle nuove funzioni la prima volta che le esegui il deployment. Non viene applicata retroattivamente alle funzioni esistenti che sono state implementate per la prima volta prima dell'entrata in vigore delle modifiche descritte in queste note di rilascio, anche se le implementi di nuovo.Best practice
Questa sezione descrive le best practice per l'utilizzo dei tentativi.
Utilizzare i tentativi per gestire gli errori temporanei
Poiché la funzione viene ritentata continuamente fino all'esecuzione riuscita, gli errori permanenti come i bug devono essere eliminati dal codice tramite test prima di attivare i nuovi tentativi. I tentativi vengono utilizzati al meglio per gestire errori intermittenti o temporanei che hanno un'alta probabilità di risoluzione al nuovo tentativo, ad esempio un endpoint di servizio instabile o un timeout.
Imposta una condizione di fine per evitare loop di tentativi ripetuti all'infinito
La best practice consiste nel proteggere la funzione da loop continui quando utilizzi i tentativi. Puoi farlo includendo una condizione di fine ben definita prima che la funzione inizi l'elaborazione. Tieni presente che questa tecnica funziona solo se la funzione viene avviata correttamente ed è in grado di valutare la condizione finale.
Un approccio semplice ma efficace è quello di eliminare gli eventi con timestamp precedenti a un determinato periodo di tempo. In questo modo si evitano esecuzioni eccessive quando gli errori sono persistenti o di durata superiore al previsto.
Ad esempio, questo snippet di codice elimina tutti gli eventi più vecchi di 10 secondi:
const eventAgeMs = Date.now() - Date.parse(event.timestamp);
const eventMaxAgeMs = 10000;
if (eventAgeMs > eventMaxAgeMs) {
console.log(`Dropping event ${event} with age[ms]: ${eventAgeMs}`);
callback();
return;
}
Utilizzare catch
con le promesse
Se i tentativi sono abilitati per la funzione, qualsiasi errore non gestito attiverà un nuovo tentativo. Assicurati che il codice acquisisca eventuali errori che non devono comportare un nuovo tentativo.
Ecco un esempio di cosa dovresti fare:
return doFooAsync().catch((err) => {
if (isFatal(err)) {
console.error(`Fatal error ${err}`);
}
return Promise.reject(err);
});
Rendere idempotenti le funzioni basate su eventi ripetibili
Le funzioni basate su eventi che possono essere riprovate devono essere idempotenti. Ecco alcune linee guida generali per rendere idempotente una funzione:
- Molte API esterne (come Stripe) ti consentono di fornire una chiave di idempotenza come parametro. Se utilizzi un'API di questo tipo, devi utilizzare l'ID evento come chiave di idempotenza.
- L'idempotenza funziona bene con la consegna "at-least-once", perché consente di riprovare in sicurezza. Pertanto, una best practice generale per scrivere codice affidabile è combinare l'idempotenza con i tentativi.
- Assicurati che il codice sia idempotente internamente. Ad esempio:
- Assicurati che le mutazioni possano verificarsi più di una volta senza modificare il risultato.
- Esegui query sullo stato del database in una transazione prima di modificarlo.
- Assicurati che tutti gli effetti collaterali siano idempotenti.
- Imponi un controllo transazionale al di fuori della funzione, indipendentemente dal codice. Ad esempio, mantieni lo stato in un punto in cui viene registrato che un determinato ID evento è già stato elaborato.
- Gestisci le chiamate di funzione duplicate fuori banda. Ad esempio, esegui una pulizia separata dopo le chiamate di funzioni duplicate.
Configura il criterio per i tentativi ripetuti
A seconda delle esigenze della tua funzione, potresti voler configurare direttamente la policy di ripetizione dei tentativi. In questo modo potrai configurare qualsiasi combinazione dei seguenti elementi:
- Ridurre la finestra di nuovi tentativi da 7 giorni a un minimo di 10 minuti.
- Modifica il tempo di backoff minimo e massimo per la strategia di ripetizione di backoff esponenziale.
- Modifica la strategia di ripetizione per riprovare immediatamente.
- Configura un argomento messaggi non recapitabili.
- Imposta un numero massimo e minimo di tentativi di consegna.
Per configurare i criteri di ripetizione:
- Scrivi una funzione HTTP.
- Utilizza l'API Pub/Sub per creare un abbonamento Pub/Sub, specificando l'URL della funzione come destinazione.
Per ulteriori informazioni sulla configurazione diretta di Pub/Sub, consulta la documentazione di Pub/Sub sulla gestione degli errori.