Sua extensão pode incluir funções do Cloud Tasks que são acionadas quando uma instância de extensão passa por qualquer um dos seguintes eventos de ciclo de vida:
- Uma instância da extensão está instalada
- Uma instância da extensão é atualizada para uma nova versão
- A configuração de uma instância de extensão foi alterada
Um dos casos de uso mais importantes desse recurso é o preenchimento de dados . Por exemplo, suponha que você esteja criando uma extensão que gera visualizações em miniatura de imagens enviadas para um bucket do Cloud Storage. O trabalho principal da sua extensão seria feito em uma função acionada pelo evento onFinalize
Cloud Storage. No entanto, apenas as imagens carregadas após a instalação da extensão serão processadas. Ao incluir em sua extensão uma função acionada pelo evento de ciclo de vida onInstall
, você também poderá gerar visualizações em miniatura de quaisquer imagens existentes quando a extensão for instalada.
Alguns outros casos de uso de acionadores de eventos de ciclo de vida incluem:
- Automatize a configuração pós-instalação (criação de registros de banco de dados, indexação, etc.)
- Se você precisar publicar alterações incompatíveis com versões anteriores, migre automaticamente os dados na atualização
Manipuladores de eventos de ciclo de vida de curta duração
Se sua tarefa puder ser executada completamente dentro da duração máxima do Cloud Functions (9 minutos usando a API de primeira geração), você poderá escrever seu manipulador de eventos de ciclo de vida como uma função única que é acionada no evento onDispatch
da fila de tarefas:
export const myTaskFunction = functions.tasks.taskQueue()
.onDispatch(async () => {
// Complete your lifecycle event handling task.
// ...
// When processing is complete, report status to the user (see below).
});
Em seguida, no arquivo extension.yaml
da sua extensão, faça o seguinte:
Registre sua função como um recurso de extensão com o conjunto de propriedades
taskQueueTrigger
. Se você definirtaskQueueTrigger
como o mapa vazio ({}
), sua extensão provisionará uma fila do Cloud Tasks usando as configurações padrão; você pode opcionalmente ajustar essas configurações .resources: - name: myTaskFunction type: firebaseextensions.v1beta.function description: >- Describe the task performed when the function is triggered by a lifecycle event properties: location: ${LOCATION} taskQueueTrigger: {}
Registre sua função como manipulador para um ou mais eventos de ciclo de vida:
resources: - ... lifecycleEvents: onInstall: function: myTaskFunction processingMessage: Resizing your existing images onUpdate: function: myOtherTaskFunction processingMessage: Setting up your extension onConfigure: function: myOtherTaskFunction processingMessage: Setting up your extension
Você pode registrar funções para qualquer um dos seguintes eventos:
onInstall
,onUpdate
eonConfigure
. Todos esses eventos são opcionais.Recomendado : se a tarefa de processamento não for necessária para que sua extensão funcione, adicione um parâmetro configurado pelo usuário que permita aos usuários escolher se desejam ativá-la.
Por exemplo, adicione um parâmetro como o seguinte:
params: - param: DO_BACKFILL label: Backfill existing images description: > Should existing, unresized images in the Storage bucket be resized as well? type: select options: - label: Yes value: true - label: No value: false
E na sua função, se o parâmetro estiver definido como
false
, saia mais cedo:export const myTaskFunction = functions.tasks.taskQueue() .onDispatch(async () => { if (!process.env.DO_BACKFILL) { await runtime.setProcessingState( "PROCESSING_COMPLETE", "Existing images were not resized." ); return; } // Complete your lifecycle event handling task. // ... });
Executando tarefas de longa duração
Se sua tarefa não puder ser concluída dentro da duração máxima do Cloud Functions, divida-a em subtarefas e execute cada subtarefa em sequência enfileirando jobs com o método TaskQueue.enqueue()
do Admin SDK.
Por exemplo, suponha que você queira preencher os dados do Cloud Firestore. Você pode dividir a coleção de documentos em partes usando cursores de consulta . Depois de processar um pedaço, avance o deslocamento inicial e enfileire outra invocação de função conforme mostrado abaixo:
import { getFirestore } from "firebase-admin/firestore";
import { getFunctions } from "firebase-admin/functions";
exports.backfilldata = functions.tasks.taskQueue().onDispatch(async (data) => {
// When a lifecycle event triggers this function, it doesn't pass any data,
// so an undefined offset indicates we're on our first invocation and should
// start at offset 0. On subsequent invocations, we'll pass an explicit
// offset.
const offset = data["offset"] ?? 0;
// Get a batch of documents, beginning at the offset.
const snapshot = await getFirestore()
.collection(process.env.COLLECTION_PATH)
.startAt(offset)
.limit(DOCS_PER_BACKFILL)
.get();
// Process each document in the batch.
const processed = await Promise.allSettled(
snapshot.docs.map(async (documentSnapshot) => {
// Perform the processing.
})
);
// If we processed a full batch, there are probably more documents to
// process, so enqueue another invocation of this function, specifying
// the offset to start with.
//
// If we processed less than a full batch, we're done.
if (processed.length == DOCS_PER_BACKFILL) {
const queue = getFunctions().taskQueue(
"backfilldata",
process.env.EXT_INSTANCE_ID
);
await queue.enqueue({
offset: offset + DOCS_PER_BACKFILL,
});
} else {
// Processing is complete. Report status to the user (see below).
}
});
Adicione a função ao seu extension.yaml
conforme descrito na seção anterior .
Status do relatório
Quando todas as suas funções de processamento forem concluídas, com êxito ou com erro, informe o status da tarefa usando os métodos de tempo de execução de extensão do SDK Admin. Os usuários podem ver esse status na página de detalhes da extensão no console do Firebase.
Conclusão bem-sucedida e erros não fatais
Para relatar a conclusão bem-sucedida e erros não fatais (erros que não colocam a extensão em um estado não funcional), use o método de tempo de execução da extensão setProcessingState()
do SDK Admin:
import { getExtensions } from "firebase-admin/extensions";
// ...
getExtensions().runtime().setProcessingState(processingState, message);
Você pode definir os seguintes estados:
Estados não fatais | |
---|---|
PROCESSING_COMPLETE | Use para relatar a conclusão bem-sucedida da tarefa. Exemplo: getExtensions().runtime().setProcessingState( "PROCESSING_COMPLETE", `Backfill complete. Successfully processed ${numSuccess} documents.` ); |
PROCESSING_WARNING | Use para relatar sucesso parcial. Exemplo: getExtensions().runtime().setProcessingState( "PROCESSING_WARNING", `Backfill complete. ${numSuccess} documents processed successfully.` + ` ${numFailed} documents failed to process. ${listOfErrors}.` + ` ${instructionsToFixTheProblem}` ); |
PROCESSING_FAILED | Use para relatar erros que impedem a conclusão da tarefa, mas não deixam a extensão inutilizável. Exemplo: getExtensions().runtime().setProcessingState( "PROCESSING_FAILED", `Backfill failed. ${errorMsg} ${optionalInstructionsToFixTheProblem}.` ); Para relatar erros que deixam a extensão inutilizável, chame |
NONE | Use para limpar o status da tarefa. Opcionalmente, você pode usar isso para limpar a mensagem de status do console (por exemplo, após algum tempo ter passado desde a configuração de getExtensions().runtime().setProcessingState("NONE"); |
Erros fatais
Se ocorrer um erro que impeça o funcionamento da extensão (por exemplo, falha em uma tarefa de configuração necessária), relate o erro fatal com setFatalError()
:
import { getExtensions } from "firebase-admin/extensions";
// ...
getExtensions().runtime().setFatalError(`Post-installation setup failed. ${errorMessage}`);
Ajustando a fila de tarefas
Se você definir a propriedade taskQueueTrigger
como {}
, sua extensão provisionará uma fila do Cloud Tasks com as configurações padrão quando uma instância de extensão for instalada. Como alternativa, você pode ajustar os limites de simultaneidade da fila de tarefas e tentar novamente o comportamento fornecendo valores específicos:
resources:
- name: myTaskFunction
type: firebaseextensions.v1beta.function
description: >-
Perform a task when triggered by a lifecycle event
properties:
location: ${LOCATION}
taskQueueTrigger:
rateLimits:
maxConcurrentDispatches: 1000
maxDispatchesPerSecond: 500
retryConfig:
maxAttempts: 100 # Warning: setting this too low can prevent the function from running
minBackoffSeconds: 0.1
maxBackoffSeconds: 3600
maxDoublings: 16
lifecycleEvents:
onInstall:
function: myTaskFunction
processingMessage: Resizing your existing images
onUpdate:
function: myTaskFunction
processingMessage: Setting up your extension
onConfigure:
function: myOtherTaskFunction
processingMessage: Setting up your extension
Consulte Configurar filas do Cloud Tasks na documentação do Google Cloud para obter detalhes sobre esses parâmetros.
Não tente especificar parâmetros de fila de tarefas passando-os para taskQueue()
. Essas configurações são ignoradas em favor da configuração em extension.yaml
e dos padrões de configuração.
Por exemplo, isso não funcionará:
export const myBrokenTaskFunction = functions.tasks
// DON'T DO THIS IN AN EXTENSION! THESE SETTINGS ARE IGNORED.
.taskQueue({
retryConfig: {
maxAttempts: 5,
minBackoffSeconds: 60,
},
rateLimits: {
maxConcurrentDispatches: 1000,
maxDispatchesPerSecond: 10,
},
})
.onDispatch(
// ...
);
A propriedade taskQueueTrigger
em extension.yaml
é a única maneira de configurar as filas de tarefas de uma extensão.
Exemplos
As extensões oficiais storage-resize-images
, firestore-bigquery-export
e firestore-translate-text
usam manipuladores de eventos de ciclo de vida para preencher dados.