Riprovare le funzioni asincrone

Questo documento descrive come richiedere asincroni (non HTTPS) in background per riprovare in caso di errore.

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 evento. Per impostazione predefinita, se una funzione la chiamata termina con un errore, la funzione non viene richiamata di nuovo e l'evento viene eliminato. Quando attivi i tentativi su una funzione basata su eventi, Cloud Functions riprova a invocare una funzione non riuscita finché non viene completata correttamente o non scade il periodo di tempo per i tentativi.

Per le funzioni di 2a generazione, questo periodo di ripetizione scade dopo 24 ore. Per le funzioni di 1ª gen., scade dopo 7 giorni. Cloud Functions esegue un nuovo tentativo con funzioni basate su eventi appena create utilizzando una strategia di backoff esponenziale, con un backoff crescente compreso tra 10 e 600 secondi. Questo criterio viene applicato alle nuove funzioni la prima volta che ne esegui il deployment. Non viene applicata retroattivamente alle funzioni esistenti di cui è stato eseguito il primo dispiegamento prima dell'applicazione delle modifiche descritte in questa nota di rilascio, anche se le funzioni vengono ridistribuite.

Quando i nuovi tentativi non sono abilitati per una funzione (impostazione predefinita), la funzione segnala sempre che è stata eseguita correttamente e i codici di risposta 200 OK potrebbero vengono visualizzate nei log. Ciò si verifica anche se la funzione ha riscontrato un errore. A capire quando la funzione rileva un errore, assicurati di segnalare errori in modo appropriato.

Perché le funzioni basate su eventi non vengono completate

In rare occasioni, una funzione potrebbe uscire prematuramente a causa di un errore interno. e per impostazione predefinita è possibile ritentare automaticamente la funzione.

Più tipicamente, una funzione basata su eventi potrebbe non riuscire a essere completata correttamente agli errori generati nel codice della funzione stessa. Ecco alcuni motivi per cui questo potrebbe accadere:

  • La funzione contiene un bug e il runtime genera un'eccezione.
  • La funzione non può raggiungere un endpoint di servizio o si verifica un timeout durante il tentativo di farlo.
  • La funzione genera intenzionalmente un'eccezione (ad esempio, quando un parametro non supera la convalida).
  • Una funzione Node.js restituisce una promessa rifiutata o passa un valore diverso da null a una richiamata.

In ognuno di questi casi, l'esecuzione della funzione viene interrotta per impostazione predefinita e l'evento viene ignorato. Per riprovare la funzione quando si verifica un errore, puoi modifica il criterio predefinito per i nuovi tentativi l'impostazione del "ritenta in caso di errore" proprietà. In questo modo l'evento viene ritentato più volte fino alla viene completata correttamente o il timeout per il nuovo tentativo scade.

Abilita o disabilita i nuovi tentativi

Configurare i tentativi di nuovo invio dalla console

Se stai creando una nuova funzione:

  1. Da nella schermata Crea funzione, in Attivatore e scegli il tipo di evento che funga da attivatore per il tuo personalizzata.
  2. Seleziona la casella di controllo Riprova in caso di errore per attivare i tentativi di nuovo invio.

Se stai aggiornando una funzione esistente:

  1. Nella pagina Panoramica di Cloud Functions, fai clic sul nome del che stai aggiornando per aprire la relativa schermata Dettagli funzione, quindi Scegli Modifica dalla barra dei menu per visualizzare il riquadro Trigger.
  2. Seleziona o deseleziona la casella di controllo Riprova in caso di errore per attivare o disattivare i tentativi di nuovo invio.

Configura i nuovi tentativi dal codice della funzione

Con Cloud Functions for Firebase, puoi abilitare i nuovi tentativi nel codice per un personalizzata. Per farlo per una funzione in background come functions.foo.onBar(myHandler);, utilizza runWith e configura un criterio di errore:

functions.runWith({failurePolicy: true}).foo.onBar(myHandler);

Se imposti true come mostrato, viene configurata una funzione per riprovare in caso di errore.

Best practice

In questa sezione vengono descritte le best practice per l'utilizzo di nuovi tentativi.

Utilizza Riprova per gestire gli errori temporanei

Poiché la funzione viene ripetuta continuamente fino a quando l'esecuzione non riesce, gli errori permanenti, come i bug, dovrebbero essere eliminati dal codice tramite test prima di abilitare i nuovi tentativi. I tentativi sono ideali per gestire errori intermittenti o temporanei con un'alta probabilità di risoluzione al successivo tentativo, ad esempio un endpoint di servizio inaffidabile o un timeout.

Imposta una condizione di fine per evitare loop infiniti di nuovi tentativi

Una best practice consiste nel proteggere la funzione dal loop continuo quando usando nuovi tentativi. Puoi farlo includendo una condizione di fine ben definita, prima dell'inizio dell'elaborazione della funzione. Tieni presente che questa tecnica funziona solo se la funzione si avvia correttamente ed è in grado di valutare la condizione di fine.

Un approccio semplice ma efficace consiste nell'ignorare gli eventi con timestamp precedenti a in un determinato momento. Ciò aiuta a evitare esecuzioni eccessive in caso di errori. duraturi o più a lungo del 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;
}

Usa catch con Promise

Se per la funzione sono abilitati i tentativi, qualsiasi errore non gestito attiverà un nuovo tentativo. Assicurati che il codice acquisisca tutti gli errori che non dovrebbero comportare un nuovo tentativo.

Ecco un esempio di ciò che dovresti fare:

return doFooAsync().catch((err) => {
    if (isFatal(err)) {
        console.error(`Fatal error ${err}`);
    }
    return Promise.reject(err);
});

Rendi idempotenti le funzioni basate su eventi ritentabili

Le funzioni basate su eventi che è possibile ritentare devono essere idempotenti. Ecco alcuni esempi linee guida generali per rendere idempotente una funzione di questo tipo:

  • 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 la chiave di idempotenza.
  • L'idempotenza funziona bene con la consegna "at-least-once", perché consente di riprova. Una best practice generale per scrivere codice affidabile è combinare idempotenza con nuovi tentativi.
  • Assicurati che il tuo codice sia internamente idempotente. Ad esempio:
    • Assicurati che le mutazioni possano verificarsi più di una volta senza modificare il risultato finale.
    • Esegui una query sullo stato del database in una transazione prima di modificarne lo stato.
    • Assicurati che tutti gli effetti collaterali siano idempotenti.
  • Impone un controllo transazionale all'esterno della funzione, indipendentemente dal codice. Ad esempio, uno stato permanente che registra un determinato ID evento sono già stati elaborati.
  • Gestire chiamate di funzione duplicate fuori banda. Ad esempio, esegui una pulizia separata che esegue la pulizia dopo chiamate di funzione duplicate.

Configura il criterio per i nuovi tentativi

A seconda delle esigenze della tua funzione, potresti voler configurare nuovo criterio di ripetizione. Questo ti consente di impostare qualsiasi combinazione di seguenti:

  • Riduci la finestra per i nuovi tentativi da 7 giorni a meno di 10 minuti.
  • Modifica il tempo di backoff minimo e massimo per il backoff esponenziale strategia di ripetizione.
  • Modifica la strategia per riprovare immediatamente.
  • Configura un argomento messaggi non recapitabili.
  • Imposta un numero massimo e minimo di tentativi di invio.

Per configurare il criterio per i nuovi tentativi:

  1. Scrivi una funzione HTTP.
  2. Usa l'API Pub/Sub per creare un abbonamento Pub/Sub, specificando l'URL della la funzione come target.

Per ulteriori informazioni sulla configurazione diretta di Pub/Sub, consulta la documentazione di Pub/Sub sulla gestione degli errori.