Enfileirar funções com o Cloud Tasks


As funções de fila de tarefas usam o Google Cloud Tasks para ajudar seu app a executar tarefas demoradas, que consomem muitos recursos ou limitadas por largura de banda de maneira assíncrona e fora do fluxo principal do aplicativo.

Por exemplo, imagine que você quer criar backups de um grande conjunto de arquivos de imagem hospedados atualmente em uma API com um limite de taxa. Para fazer o consumo responsável dessa API, precisamos respeitar esses limites. Além disso, esse tipo de job de longa duração pode ser vulnerável a falhas devido a tempos limite e limites de memória.

Para atenuar essa complexidade, grave uma função de fila de tarefas que defina opções básicas de tarefa, como scheduleTime e dispatchDeadline e a distribua para uma fila no Cloud Tasks. O ambiente do Cloud Tasks foi projetado especificamente para garantir um controle de congestionamento e políticas de repetição eficientes para esses tipos de operações.

O SDK do Firebase para o Cloud Functions para Firebase v3.20.1 e versões posteriores interopera com o SDK Admin do Firebase v10.2.0 e versões mais recentes para oferecer suporte a funções da fila de tarefas.

O uso de funções da fila de tarefas com o Firebase pode resultar em cobranças pelo processamento do Cloud Tasks. Consulte Preços do Cloud Tasks para mais informações.

Como criar funções da fila de tarefas

Para usar as funções da fila de tarefas, siga este fluxo de trabalho:

  1. Grave uma função da fila de tarefas usando o SDK do Firebase para Cloud Functions.
  2. Teste suas funções localmente usando o Pacote de emuladores locais do Firebase.
  3. Implante a função com a CLI do Firebase. Ao implantar a função de fila de tarefas pela primeira vez, a CLI vai criar uma fila de tarefas no Cloud Tasks com opções (limitação de taxa e nova tentativa) especificadas no código-fonte.
  4. Adicione tarefas à fila de tarefas recém-criada, transmitindo parâmetros para configurar uma programação de execução. Para isso, escreva o código usando o SDK Admin e implante-o no Cloud Functions para Firebase.

Como criar funções da fila de tarefas

Use onDispatch para começar a escrever funções da fila de tarefas. Uma parte importante de escrever uma função da fila de tarefas é definir uma configuração de limitação de taxa e nova tentativa por fila. Os exemplos de código desta página têm como base um app que configura um serviço de backup de todas as imagens do site de fotos astronômicas diárias da NASA (link em inglês):

Configuração da fila de tarefas

As funções da fila de tarefas têm um conjunto avançado de configurações para controlar com precisão os limites de taxa e o comportamento de repetição de uma fila de tarefas:

exports.backupApod = functions
    .runWith( {secrets: ["NASA_API_KEY"]})
    .tasks.taskQueue({
      retryConfig: {
        maxAttempts: 5,
        minBackoffSeconds: 60,
      },
      rateLimits: {
        maxConcurrentDispatches: 6,
      },
    }).onDispatch(async (data) => {
  • retryConfig.maxAttempts=5: cada tarefa na fila é repetida automaticamente até cinco vezes. Isso nos ajuda a reduzir falhas transitórias, como erros de rede, ou a interrupção temporária de um serviço externo e dependente.
  • retryConfig.minBackoffSeconds=60: cada tarefa é executada novamente após um intervalo mínimo de 60 segundos. Com isso, temos um grande buffer entre cada tentativa, e não há pressa para realizar as cinco tentativas muito rapidamente.
  • rateLimits.maxConcurrentDispatch=6: são enviadas, no máximo, seis tarefas em um determinado momento. Isso ajuda a garantir um fluxo estável de solicitações para a função, além de reduzir o número de instâncias ativas e inicializações a frio.

Como testar funções da fila de tarefas usando o Pacote de emuladores locais do Firebase

As funções da fila de tarefas no Pacote de emuladores locais do Firebase são expostas como funções HTTP simples. Para testar uma função de tarefa emulada, envie uma solicitação HTTP POST com um payload de dados json:

 # start the Firebase Emulators
 firebase emulators:start

 # trigger the emulated task queue function
 curl \
  -X POST                                            # An HTTP POST request...
  -H "content-type: application/json" \              # ... with a JSON body
  http://localhost:$PORT/$PROJECT_ID/$REGION/$NAME \ # ... to function url
  -d '{"data": { ... some data .... }}'              # ... with JSON encoded data

Como implantar a função da fila de tarefas

Implante a função da fila de tarefas usando a CLI do Firebase:

$ firebase deploy --only functions:backupApod

Ao implantar a função de fila de tarefas pela primeira vez, a CLI cria uma fila de tarefas no Cloud Tasks com opções (limitação de taxa e nova tentativa) especificadas no código-fonte.

Se você encontrar erros de permissão ao implantar funções, verifique se os papéis do IAM apropriados estão atribuídos ao usuário que executa os comandos de implantação.

Enfileirar a função

As funções da fila de tarefas podem ser enfileiradas no Cloud Tasks partindo de um ambiente de servidor confiável, como o Cloud Functions para Firebase, usando o SDK Admin do Firebase para Node.js. Se você não tiver experiência com os SDKs Admin, consulte Adicionar o Firebase a um servidor para começar.

Em um fluxo típico, o SDK Admin cria uma nova tarefa, enfileira no Cloud Tasks e define a configuração dela:

exports.enqueueBackupTasks = functions.https.onRequest(
async (_request, response) => {
  const queue = getFunctions().taskQueue("backupApod");
  const enqueues = [];
  for (let i = 0; i <= 10; i += 1) {
    // Enqueue each task with i*60 seconds delay. Our task queue function
    // should process ~1 task/min.
    const scheduleDelaySeconds = i * 60 
    enqueues.push(
        queue.enqueue(
          { id: `task-${i}` },
          {
            scheduleDelaySeconds,
            dispatchDeadlineSeconds: 60 * 5 // 5 minutes
          },
        ),
    );
  }
  await Promise.all(enqueues);
  response.sendStatus(200);

});
  • scheduleDelaySeconds: o exemplo de código tenta distribuir a execução das tarefas associando um atraso de N minutos à tarefa N. Isso se traduz no acionamento de aproximadamente 1 tarefa/minuto. Também é possível usar scheduleTime se quiser que o Cloud Tasks acione uma tarefa em um horário específico.
  • dispatchDeadlineSeconds: o tempo máximo que o Cloud Tasks vai aguardar a conclusão de uma tarefa. O Cloud Tasks vai tentar realizar a tarefa novamente após a configuração da nova tentativa da fila ou até que esse prazo seja atingido. No exemplo, a fila é configurada para tentar realizar a tarefa novamente até cinco vezes, mas a tarefa é cancelada automaticamente se todo o processo (incluindo novas tentativas) levar mais de cinco minutos.

Solução de problemas

Ativar a geração de registros do Cloud Tasks

Os registros do Cloud Tasks têm informações de diagnóstico úteis, como o status da solicitação associada a uma tarefa. Por padrão, os registros do Cloud Tasks são desativados devido ao grande volume de registros que podem ser gerados no projeto. Recomendamos ativar os registros de depuração enquanto você desenvolve e depura ativamente as funções da fila de tarefas. Consulte Como ativar a geração de registros.

Permissões do IAM

É possível ver erros PERMISSION DENIED ao enfileirar tarefas ou quando o Cloud Tasks tenta invocar as funções da fila de tarefas. Verifique se o projeto tem as seguintes vinculações do IAM:

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member=serviceAccount:${PROJECT_ID}@appspot.gserviceaccount.com \
  --role=roles/cloudtasks.enqueuer
  • A identidade usada para enfileirar tarefas para o Cloud Tasks precisa de permissão para usar a conta de serviço associada a uma tarefa no Cloud Tasks.

    No exemplo, a conta de serviço padrão do App Engine.

Consulte a documentação do Google Cloud IAM para ver instruções sobre como adicionar a conta de serviço padrão do App Engine como um usuário da conta de serviço padrão do App Engine.

gcloud functions add-iam-policy-binding $FUNCTION_NAME \
  --region=us-central1 \
  --member=serviceAccount:${PROJECT_ID}@appspot.gserviceaccount.com \
  --role=roles/cloudfunctions.invoker