Sua extensão pode incluir funções do Cloud Tasks que são acionadas quando uma instância de extensão passa por um dos seguintes eventos de ciclo de vida:
- Uma instância da extensão está instalada
- Uma instância da extensão foi atualizada para uma nova versão
- A configuração de uma instância de extensão é 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 gere visualizações em miniatura das imagens enviadas a um bucket do Cloud Storage. O principal trabalho da sua extensão
seria feito em uma função acionada pelo evento onFinalize
Cloud Storage.
No entanto, apenas as imagens enviadas após a instalação da extensão serão processadas. Ao incluir na sua extensão uma função acionada pelo evento de ciclo de vida onInstall
, você também pode gerar visualizações em miniatura de qualquer imagem existente quando a extensão estiver instalada.
Alguns outros casos de uso de acionadores de eventos do ciclo de vida incluem:
- Automatizar a configuração pós-instalação (criação de registros do banco de dados, indexação etc.)
- Se você precisar publicar alterações incompatíveis com versões anteriores, migre os dados automaticamente
Manipuladores de eventos de ciclo de vida de curta duração
Se a tarefa puder ser executada completamente dentro da duração máxima do Cloud Functions (9 minutos usando a API de primeira geração), será possível escrever o manipulador de eventos de ciclo de vida como uma única função que é acionado 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. É possível 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 um 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
É possível 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 a extensão funcionar, adicione um parâmetro configurado pelo usuário que permita aos usuários escolher se ela será ativada.
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
Na sua função, se o parâmetro estiver definido como
false
, saia antecipadamente: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. // ... });
Como executar tarefas de longa duração
Se não for possível concluir sua tarefa dentro da duração máxima do Cloud Functions, divida-a em subtarefas e realize cada subtarefa em sequência enfileirando os jobs com o método TaskQueue.enqueue()
do SDK Admin.
Por exemplo, suponha que você queira preencher dados de Cloud Firestore. É possível dividir a coleção de documentos em partes usando cursores de consulta. Depois de processar um bloco, 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 extension.yaml
, conforme descrito na
seção anterior.
Status do relatório
Quando todas as funções de processamento forem concluídas, seja com êxito ou com um erro, informe o status da tarefa usando os métodos de ambiente de execução da extensão do SDK Admin. Os usuários podem conferir esse status na página de detalhes da extensão no console do Firebase.
Conclusão e erros não fatais
Para relatar erros de conclusão e não fatal (erros que não colocam a extensão em um estado não funcional), use o método de ambiente de execução da extensão setProcessingState()
do SDK Admin:
import { getExtensions } from "firebase-admin/extensions";
// ...
getExtensions().runtime().setProcessingState(processingState, message);
É possível definir os seguintes estados:
Estados não fatais | |
---|---|
PROCESSING_COMPLETE |
Use para informar a conclusão de uma tarefa. Exemplo: getExtensions().runtime().setProcessingState( "PROCESSING_COMPLETE", `Backfill complete. Successfully processed ${numSuccess} documents.` ); |
PROCESSING_WARNING |
Use para informar 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 informar erros que deixam a extensão inutilizável, chame |
NONE |
Use para limpar o status da tarefa. Opcionalmente, você pode usar para limpar a mensagem de status do console (por exemplo, depois de um certo tempo desde a configuração do getExtensions().runtime().setProcessingState("NONE"); |
Erros fatais
Se ocorrer um erro que impede o funcionamento da extensão, por exemplo, se uma tarefa obrigatória de configuração falhar, informe o erro fatal com setFatalError()
:
import { getExtensions } from "firebase-admin/extensions";
// ...
getExtensions().runtime().setFatalError(`Post-installation setup failed. ${errorMessage}`);
Como ajustar a fila de tarefas
Se você definir a propriedade taskQueueTrigger
como {}
, sua extensão vai provisionar uma fila do Cloud Tasks com as configurações padrão, quando uma instância de extensão for instalada. Como alternativa, é possível ajustar os limites de simultaneidade da fila de tarefas e o comportamento de repetição 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 nos documentos do Google Cloud para conferir detalhes sobre esses parâmetros.
Não tente especificar parâmetros da fila de tarefas passando-os para taskQueue()
.
Essas configurações são ignoradas em favor da configuração em extension.yaml
e
os padrões de configuração.
Por exemplo, esta abordagem não vai 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 de eventos de ciclo de vida para preencher dados.