Votre extension peut inclure Cloud Tasks fonctions qui se déclenchent lorsqu'une instance d'extension passe par l'un des événements de cycle de vie suivants :
- Une instance de l'extension est installée.
- Une instance de l'extension est mise à jour vers une nouvelle version.
- La configuration d'une instance d'extension est modifiée.
L'un des cas d'utilisation les plus importants de cette fonctionnalité est le remplissage des données. Supposons, par
exemple, que vous créez une extension qui génère des aperçus miniatures
des images importées dans un Cloud Storage bucket. Le travail principal de votre extension
serait effectué dans une fonction déclenchée par l'événement onFinalize Cloud Storage.
Toutefois, seules les images importées après l'installation de l'extension seraient traitées. En incluant dans votre extension une fonction déclenchée par l'événement de cycle de vie
onInstall vous pouvez également générer des aperçus miniatures des images
existantes lors de l'installation de l'extension.
Voici quelques autres cas d'utilisation des déclencheurs d'événements de cycle de vie :
- Automatiser la configuration post-installation (création d'enregistrements de base de données, indexation, etc.)
- Si vous devez publier des modifications rétrocompatibles, migrez automatiquement les données lors de la mise à jour.
Gestionnaires d'événements de cycle de vie de courte durée
Si votre tâche peut s'exécuter complètement dans la
durée Cloud Functionsmaximale (9
minutes à l'aide de l'API de première génération), vous pouvez écrire votre gestionnaire d'événements de cycle de vie
en tant que fonction unique qui se déclenche sur l'événement onDispatch de la file d'attente de tâches :
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).
});
Ensuite, dans le fichier extension.yaml de votre extension, procédez comme suit :
Enregistrez votre fonction en tant que ressource d'extension avec la propriété
taskQueueTriggerdéfinie. Si vous définisseztaskQueueTriggersur la carte vide ({}), votre extension provisionnera une file d'attente Cloud Tasks à l'aide des paramètres par défaut . Vous pouvez éventuellement ajuster ces paramètres.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: {}Enregistrez votre fonction en tant que gestionnaire pour un ou plusieurs événements de cycle de vie :
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 extensionVous pouvez enregistrer des fonctions pour l'un des événements suivants :
onInstall,onUpdateetonConfigure. Tous ces événements sont facultatifs.Recommandé : Si la tâche de traitement n'est pas nécessaire au fonctionnement de votre extension, ajoutez un paramètre configuré par l'utilisateur qui lui permet de choisir s'il souhaite l'activer.
Par exemple, ajoutez un paramètre comme celui-ci :
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: falseEt dans votre fonction, si le paramètre est défini sur
false, quittez-la rapidement :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. // ... });
Effectuer des tâches de longue durée
Si votre tâche ne peut pas être effectuée dans la durée maximale Cloud Functions,
divisez-la en sous-tâches et exécutez chaque sous-tâche de manière séquentielle en mettant en file d'attente
des tâches avec la méthode TaskQueue.enqueue()
du SDK Admin.
Supposons, par exemple, que vous souhaitez remplir les données Cloud Firestore. Vous pouvez diviser la collection de documents en blocs à l'aide de curseurs de requête. Après avoir traité un bloc, avancez le décalage de début et mettez en file d'attente une autre invocation de fonction, comme indiqué ci-dessous :
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).
}
});
Ajoutez la fonction à votre extension.yaml comme décrit dans la
section précédente.
État du rapport
Une fois toutes vos fonctions de traitement terminées, qu'elles aient réussi ou qu'elles aient généré une erreur, signalez l'état de la tâche à l'aide des méthodes d'exécution d'extension du SDK Admin. Les utilisateurs peuvent voir cet état sur la page des détails de l'extension dans la Firebase console.
Achèvement réussi et erreurs non fatales
Pour signaler la réussite et les erreurs non fatales (erreurs qui ne mettent pas l'extension dans un état non fonctionnel), utilisez la méthode d'exécution d'extension setProcessingState() du SDK Admin :
import { getExtensions } from "firebase-admin/extensions";
// ...
getExtensions().runtime().setProcessingState(processingState, message);
Vous pouvez définir les états suivants :
| États non fatals | |
|---|---|
PROCESSING_COMPLETE |
Utilisez-le pour signaler la réussite de la tâche. Exemple : getExtensions().runtime().setProcessingState( "PROCESSING_COMPLETE", `Backfill complete. Successfully processed ${numSuccess} documents.` ); |
PROCESSING_WARNING |
Utilisez-le pour signaler une réussite partielle. Exemple : getExtensions().runtime().setProcessingState( "PROCESSING_WARNING", `Backfill complete. ${numSuccess} documents processed successfully.` + ` ${numFailed} documents failed to process. ${listOfErrors}.` + ` ${instructionsToFixTheProblem}` ); |
PROCESSING_FAILED |
Utilisez-le pour signaler les erreurs qui empêchent la tâche de se terminer, mais qui ne rendent pas l'extension inutilisable. Exemple : getExtensions().runtime().setProcessingState( "PROCESSING_FAILED", `Backfill failed. ${errorMsg} ${optionalInstructionsToFixTheProblem}.` ); Pour signaler les erreurs qui rendent l'extension inutilisable, appelez
|
NONE |
Utilisez-le pour effacer l'état de la tâche. Vous pouvez également l'utiliser pour effacer
le message d'état de la console (par exemple, après un certain temps depuis la définition de getExtensions().runtime().setProcessingState("NONE"); |
Erreurs critiques
Si une erreur empêche l'extension de fonctionner (par exemple, si une tâche de configuration requise échoue), signalez l'erreur critique avec setFatalError() :
import { getExtensions } from "firebase-admin/extensions";
// ...
getExtensions().runtime().setFatalError(`Post-installation setup failed. ${errorMessage}`);
Ajuster la file d'attente de tâches
Si vous définissez la propriété taskQueueTrigger sur {}, votre extension provisionnera une file d'attente Cloud Tasks avec les paramètres par défaut lors de l'installation d'une instance d'extension. Vous pouvez également ajuster les limites de simultanéité et le comportement de nouvelle tentative de la file d'attente de tâches en fournissant des valeurs spécifiques :
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
Pour en savoir plus sur ces paramètres, consultez la section Configurer des files d'attente Cloud Tasks dans la documentation Google Cloud.
N'essayez pas de spécifier les paramètres de la file d'attente de tâches en les transmettant à taskQueue().
Ces paramètres sont ignorés au profit de la configuration dans extension.yaml et des valeurs par défaut de configuration.
Par exemple, cela ne fonctionnera pas :
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 propriété taskQueueTrigger dans extension.yaml est la seule façon de configurer les files d'attente de tâches d'une extension.
Exemples
Les extensions officielles storage-resize-images,
firestore-bigquery-export,
et firestore-translate-text
utilisent toutes des gestionnaires d'événements de cycle de vie pour remplir les données.