Confira tudo que foi anunciado no Firebase Summit e veja como usar o Firebase para acelerar o desenvolvimento de apps e executar os aplicativos com confiança. Saiba mais

Repetir funções assíncronas

Mantenha tudo organizado com as coleções Salve e categorize o conteúdo com base nas suas preferências.

Este documento descreve como você pode solicitar funções de segundo plano assíncronas (não HTTPS) para tentar novamente em caso de falha.

Semântica de repetição

O Cloud Functions garante a execução de pelo menos uma vez de uma função orientada a eventos para cada evento emitido por uma fonte de evento. No entanto, por padrão, se uma invocação de função terminar com um erro, a função não será invocada novamente e o evento será descartado. Ao habilitar novas tentativas em uma função orientada a eventos, o Cloud Functions tentará novamente uma invocação de função com falha até que ela seja concluída com sucesso ou a janela de novas tentativas expire (por padrão, após 7 dias).

Quando novas tentativas não estão habilitadas para uma função, que é o padrão, a função sempre relata que foi executada com sucesso e códigos de resposta 200 OK podem aparecer em seus logs. Isso ocorre mesmo se a função encontrar um erro. Para deixar claro quando sua função encontra um erro, certifique-se de relatar os erros adequadamente.

Por que as funções orientadas a eventos não são concluídas

Em raras ocasiões, uma função pode ser encerrada prematuramente devido a um erro interno e, por padrão, a função pode ou não ser repetida automaticamente.

Normalmente, uma função orientada a eventos pode não ser concluída com êxito devido a erros gerados no próprio código da função. Algumas das razões pelas quais isso pode acontecer são as seguintes:

  • A função contém um bug e o tempo de execução lança uma exceção.
  • A função não pode atingir um ponto de extremidade de serviço ou atinge o tempo limite ao tentar alcançar o ponto de extremidade.
  • A função lança intencionalmente uma exceção (por exemplo, quando um parâmetro falha na validação).
  • Quando as funções escritas em Node.js retornam uma promessa rejeitada ou passam um valor não null para um retorno de chamada.

Em qualquer um dos casos acima, a função para de executar por padrão e o evento é descartado. Se você quiser repetir a função quando ocorrer um erro, poderá alterar a política de repetição padrão definindo a propriedade "repetir em caso de falha" . Isso faz com que o evento seja repetido repetidamente por vários dias até que a função seja concluída com êxito.

Ativando e desativando novas tentativas

Como usar o Console do GCP

Você pode ativar ou desativar novas tentativas no Console do GCP da seguinte maneira:

  1. Acesse a página Visão geral do Cloud Functions no Cloud Platform Console.

  2. Clique em Criar função . Como alternativa, clique em uma função existente para acessar sua página de detalhes e clique em Editar .

  3. Preencha os campos obrigatórios para a sua função.

  4. Certifique-se de que o campo Acionador esteja definido como um tipo de acionador baseado em evento, como Cloud Pub/Sub ou Cloud Storage.

  5. Expanda as configurações avançadas clicando em Mais .

  6. Marque ou desmarque a caixa Tentar novamente em caso de falha .

No código de função

Com o Cloud Functions para Firebase, você pode habilitar novas tentativas no código de uma função. Para fazer isso para uma função em segundo plano, como functions.foo.onBar(myHandler); , use runWith e configure uma política de falha:

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

Definir true conforme mostrado configura uma função para tentar novamente em caso de falha.

Melhores Práticas

Esta seção descreve as melhores práticas para usar novas tentativas.

Use a repetição para lidar com erros transitórios

Como sua função é repetida continuamente até a execução bem-sucedida, erros permanentes, como bugs, devem ser eliminados de seu código por meio de testes antes de permitir novas tentativas. As novas tentativas são mais bem usadas para lidar com falhas intermitentes/transitórias que têm uma alta probabilidade de resolução após uma nova tentativa, como um endpoint de serviço inconsistente ou tempo limite.

Defina uma condição final para evitar loops infinitos de repetição

É uma prática recomendada proteger sua função contra loop contínuo ao usar novas tentativas. Você pode fazer isso incluindo uma condição final bem definida, antes que a função comece a processar. Observe que esta técnica só funciona se sua função iniciar com sucesso e for capaz de avaliar a condição final.

Uma abordagem simples, mas eficaz, é descartar eventos com timestamps anteriores a um determinado horário. Isso ajuda a evitar execuções excessivas quando as falhas são persistentes ou duram mais do que o esperado.

Por exemplo, este trecho de código descarta todos os eventos com mais de 10 segundos:

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;
}

Use catch com promessas

Se sua função tiver novas tentativas ativadas, qualquer erro não tratado acionará uma nova tentativa. Certifique-se de que seu código capture quaisquer erros que não devam resultar em uma nova tentativa.

Aqui está um exemplo do que você deve fazer:

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

Tornar idempotentes as funções orientadas a eventos que podem ser repetidas

As funções orientadas a eventos que podem ser repetidas devem ser idempotentes. Aqui estão algumas diretrizes gerais para tornar essa função idempotente:

  • Muitas APIs externas (como Stripe) permitem fornecer uma chave de idempotência como parâmetro. Se você estiver usando essa API, deverá usar o ID do evento como a chave de idempotência.
  • A idempotência funciona bem com a entrega pelo menos uma vez, porque torna segura a repetição. Portanto, uma prática recomendada geral para escrever código confiável é combinar idempotência com novas tentativas.
  • Certifique-se de que seu código seja internamente idempotente. Por exemplo:
    • Certifique-se de que as mutações possam ocorrer mais de uma vez sem alterar o resultado.
    • Consulte o estado do banco de dados em uma transação antes de alterar o estado.
    • Certifique-se de que todos os efeitos colaterais sejam idempotentes.
  • Imponha uma verificação transacional fora da função, independente do código. Por exemplo, persista o estado em algum lugar registrando que um determinado ID de evento já foi processado.
  • Lide com chamadas de função duplicadas fora de banda. Por exemplo, tenha um processo de limpeza separado que limpe após chamadas de função duplicadas.