Tu extensión puede incluir funciones de Cloud Tasks que se activan cuando una instancia de extensión pasa por cualquiera de los siguientes eventos del ciclo de vida:
- Cuando se instala una instancia de la extensión
- Cuando se actualiza una instancia de la extensión a una versión nueva
- Cuando se cambia la configuración de una instancia de extensión
Uno de los casos de uso más importantes de esta función es el reabastecimiento de datos. Por
ejemplo, supongamos que vas a compilar una extensión que genera vistas previas en miniatura
de las imágenes subidas a un bucket de Cloud Storage. El trabajo principal de la extensión
se realizaría en una función activada por el evento Cloud Storage de onFinalize
.
Sin embargo, solo se procesarán las imágenes subidas después de que se instale la
extensión. Cuando incluyes en tu extensión una función activada por el
evento del ciclo de vida de onInstall
, también puedes generar vistas previas en miniatura de cualquier imagen
existente cuando se instale la extensión.
Estos son otros casos de uso de los activadores de eventos de ciclo de vida:
- Automatizar la configuración posterior a la instalación (crear registros de base de datos, indexación, etcétera)
- Migrar automáticamente los datos cuando se actualicen (si tienes que publicar cambios que son incompatibles con versiones anteriores)
Controladores de eventos de ciclo de vida de corta duración
Si tu tarea puede ejecutarse completamente dentro de la
duración máxima de Cloud Functions (9
minutos con la API de primera generación), puedes escribir el controlador de eventos
de ciclo de vida como una sola función. que se activa en el evento onDispatch
de la lista de tareas en cola:
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).
});
Luego, haz lo siguiente en el archivo extension.yaml
de tu extensión:
Registra tu función como un recurso de extensión con el conjunto de propiedades
taskQueueTrigger
. Si configurastaskQueueTrigger
en la asignación vacía ({}
), tu extensión aprovisionará una cola de Cloud Tasks con la configuración predeterminada. De manera opcional, puedes ajustar esta configuración.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: {}
Registra tu función como controlador de uno o más eventos del 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
Puedes registrar funciones para cualquiera de los siguientes eventos:
onInstall
,onUpdate
yonConfigure
. Todos estos eventos son opcionales.Recomendación: Si no se requiere la tarea de procesamiento para que funcione la extensión, agrega un parámetro configurado por el usuario que permita a los usuarios elegir si desean habilitarla.
Por ejemplo, agrega un parámetro como el siguiente:
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
También, si en la función el parámetro está configurado como
false
, sal antes: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. // ... });
Realiza tareas de larga duración
Si tu tarea no se puede completar dentro de la duración máxima de Cloud Functions,
divídela en subtareas y realiza cada una en secuencia. Para ello, coloca trabajos en cola
con el método TaskQueue.enqueue()
del SDK de Admin.
Por ejemplo, supongamos que deseas reabastecer los datos de Cloud Firestore. Puedes dividir la colección de documentos en fragmentos con cursores de consulta. Después de procesar un fragmento, avanza el desplazamiento inicial y pon en cola otra invocación de función como se muestra a continuación:
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).
}
});
Agrega la función a tu extension.yaml
como se describió en la
sección anterior.
Estado de los informes
Cuando se completen todas tus funciones de procesamiento, ya sea de forma correcta o con un error, informa el estado de la tarea con los métodos de tiempo de ejecución de la extensión del SDK de Admin. Los usuarios pueden ver este estado en la página de detalles de la extensión en Firebase console.
Finalización correcta y errores recuperables
Para informar que la extensión se completó correctamente y los errores recuperables (errores que no dejan la extensión
en un estado no funcional), usa el método setProcessingState()
de tiempo de ejecución de la extensión del
SDK de Admin:
import { getExtensions } from "firebase-admin/extensions";
// ...
getExtensions().runtime().setProcessingState(processingState, message);
Puedes configurar los siguientes estados:
Estados recuperables | |
---|---|
PROCESSING_COMPLETE |
Se usa para informar que la tarea se completó correctamente. Ejemplo: getExtensions().runtime().setProcessingState( "PROCESSING_COMPLETE", `Backfill complete. Successfully processed ${numSuccess} documents.` ); |
PROCESSING_WARNING |
Se usa para informar el éxito parcial. Ejemplo: getExtensions().runtime().setProcessingState( "PROCESSING_WARNING", `Backfill complete. ${numSuccess} documents processed successfully.` + ` ${numFailed} documents failed to process. ${listOfErrors}.` + ` ${instructionsToFixTheProblem}` ); |
PROCESSING_FAILED |
Se usa para informar errores que impiden que la tarea se complete, pero que no dejan la extensión inutilizable. Ejemplo: getExtensions().runtime().setProcessingState( "PROCESSING_FAILED", `Backfill failed. ${errorMsg} ${optionalInstructionsToFixTheProblem}.` ); Para informar errores que sí dejan la extensión inutilizable, llama a
|
NONE |
Se usa para borrar el estado de la tarea. De forma opcional, puedes usar esto para borrar
el mensaje de estado de la consola (por ejemplo, después de que haya transcurrido un
tiempo después de configurar getExtensions().runtime().setProcessingState("NONE"); |
Errores no recuperables
Si se produce un error que impide el funcionamiento de la extensión, por
ejemplo, una tarea de configuración requerida con errores, informa el error no recuperable con
setFatalError()
:
import { getExtensions } from "firebase-admin/extensions";
// ...
getExtensions().runtime().setFatalError(`Post-installation setup failed. ${errorMessage}`);
Ajusta la lista de tareas en cola
Si configuras la propiedad taskQueueTrigger
en {}
, tu extensión
aprovisionará una cola de Cloud Tasks con la configuración predeterminada cuando se instale
una instancia de extensión. Como alternativa, puedes ajustar los límites de simultaneidad de la lista de tareas en cola
y reintentar el comportamiento proporcionando 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
Consulta Configura colas de Cloud Tasks en los documentos de Google Cloud para obtener detalles sobre estos parámetros.
No intentes especificar parámetros de la lista de tareas en cola pasándolos a taskQueue()
.
Estos parámetros de configuración se ignoran para dar lugar a la configuración en extension.yaml
y
los valores predeterminados de la configuración.
Por ejemplo, esto no 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(
// ...
);
La propiedad taskQueueTrigger
en extension.yaml
es la única forma de configurar
las listas de tareas en cola de una extensión.
Ejemplos
Las extensiones oficiales de storage-resize-images
,
firestore-bigquery-export
y firestore-translate-text
usan controladores del evento de ciclo de vida para reabastecer datos.