Créer des tâches d'envoi

Cette page explique comment créer des tâches et les placer dans des files d'attente d'envoi. Lorsque vous souhaitez traiter une tâche, vous devez créer un objet de tâche et le placer dans une file d'attente. Vous pouvez spécifier explicitement le service et le gestionnaire qui traitent la tâche, et éventuellement transmettre au gestionnaire des données spécifiques à la tâche. Vous pouvez également ajuster la configuration de la tâche, par exemple en planifiant une heure future d'exécution ou en limitant le nombre de nouvelles tentatives en cas d'échec.

Créer une tâche

Pour créer une tâche et la placer en file d'attente, appelez la fonction taskqueue.add(). Le code suivant crée une tâche qui cible le service nommé worker et appelle son gestionnaire en définissant l'url /update-counter :

class EnqueueTaskHandler(webapp2.RequestHandler):
    def post(self):
        amount = int(self.request.get('amount'))

        task = taskqueue.add(
            url='/update_counter',
            target='worker',
            params={'amount': amount})

        self.response.write(
            'Task {} enqueued, ETA {}.'.format(task.name, task.eta))

Vous pouvez également créer un objet Task et appeler sa méthode add().

Spécifier le service de nœuds de calcul

Lorsqu'une tâche est extraite de sa file d'attente, le service de la file d'attente des tâches l'envoie à un service de travail. Chaque tâche a une cible et une URL qui déterminent le service et le gestionnaire qui l'effectueront.

target

La cible spécifie le service qui recevra la requête HTTP pour effectuer la tâche. Il s'agit d'une chaîne qui spécifie un service, une version ou une instance dans une forme canonique. Voici les formes les plus courantes :

    service
    version.service
    instance.version.service

La chaîne cible précède le nom de domaine de votre application. La cible d'une tâche peut être définie de trois façons :

  • Déclarez la cible au moment de créer la tâche. Vous pouvez alors la définir explicitement à l'aide du paramètre target dans la fonction taskqueue.add (). Reportez-vous à l'exemple ci-dessus.

  • Incluez une instruction target lorsque vous définissez une file d'attente dans le fichier queue.yaml, comme vous le faites pour définir queue-blue. Toutes les tâches ajoutées à une file d'attente avec un élément target utiliseront cette cible, même si une autre cible était affectée à la tâche au moment de sa création.

  • Si aucune cible n'est spécifiée selon l'une des deux méthodes précédentes, la cible de la tâche correspond alors à la version du service qui la met en file d'attente. Notez que si vous placez ainsi une tâche issue du service et de la version par défaut en file d'attente, et que la version par défaut change avant que la tâche ne soit lancée, cette dernière s'exécutera dans la nouvelle version par défaut.

url

L'élément url sélectionne l'un des gestionnaires du service cible qui effectuera la tâche.

L'élément url doit respecter l'un des modèles d'URL du gestionnaire du service cible. L'élément url peut comprendre des paramètres de requête si la méthode spécifiée dans la tâche est GET ou PULL. Si aucune url n'est spécifiée, l'URL par défaut /_ah/queue/[QUEUE_NAME] est utilisée, où [QUEUE_NAME] correspond au nom de la file d'attente de la tâche.

Transmettre des données au gestionnaire

Vous pouvez transmettre des données au gestionnaire en tant que paramètres de requête dans l'URL de la tâche, mais seulement si la méthode spécifiée dans la tâche est GET ou PULL.

Vous pouvez également utiliser les champs payload ou params pour ajouter des données à votre tâche.

Ces trois appels sont équivalents :

taskqueue.add(method=GET, url='/update-counter?key=blue', target='worker')
taskqueue.add(url='/update-counter', params={'key': 'blue'}, target='worker')
taskqueue.add(url='/update-counter', payload="{'key': 'blue'}", target='worker')

Remarque :

  • La charge est livrée dans le corps de la requête HTTP.
  • Ne spécifiez pas "params" si vous utilisez la méthode POST avec une charge utile, ou si vous utilisez la méthode GET et que vous avez inclus un élément "url" avec des paramètres de requête.

Nommer une tâche

Lorsque vous créez une tâche, App Engine lui attribue un nom unique par défaut. Vous pouvez toutefois attribuer votre propre nom à une tâche en utilisant le paramètre name. Les tâches nommées présentent l'avantage d'être dédupliquées, ce qui signifie qu'en recourant à des noms de tâche, vous avez l'assurance que les tâches ne sont ajoutées qu'une seule fois. La déduplication demeure active pendant neuf jours après l'achèvement ou la suppression de la tâche.

Notez que la logique de déduplication a un impact significatif sur les performances, entraînant des latences accrues et des taux d'erreur potentiellement plus élevés pour les tâches nommées. Ces effets peuvent être considérablement augmentés si les tâches sont nommées de manière séquentielle, par exemple avec des horodatages. Par conséquent, si vous attribuez vos propres noms, nous vous recommandons d'utiliser un préfixe distribué de manière homogène pour les noms de tâches, tel qu'un hachage du contenu.

Si vous attribuez vos propres noms à des tâches, notez que leur longueur maximale est de 500 caractères et qu'ils peuvent contenir des majuscules, des minuscules, des chiffres, des traits de soulignement et des traits d'union.

taskqueue.add(url='/url/path', name='first-try')

Ajouter des tâches de manière asynchrone

Par défaut, les appels qui ajoutent des tâches aux files d'attente sont synchrones. Dans la plupart des scénarios, les appels synchrones fonctionnent correctement. Généralement, l'ajout d'une tâche à une file d'attente s'effectue rapidement. Un faible pourcentage d'opérations d'ajout de tâches peut prendre beaucoup plus de temps, mais le temps moyen d'ajout d'une tâche est inférieur à 5 ms.

Les opérations d'ajout de tâches à différentes files d'attente ne peuvent pas être regroupées par lots. Par conséquent, l'API Task Queue propose également des appels asynchrones qui vous permettent d'ajouter ces tâches en parallèle, ce qui réduit encore davantage cette latence. Ces appels sont utiles si vous créez une application extrêmement sensible à la latence, qui doit effectuer plusieurs opérations d'ajout de tâches à différentes files d'attente en même temps.

Si vous souhaitez effectuer des appels asynchrones vers une file d'attente de tâches, utilisez les méthodes asynchrones proposées par la classe Queue et l'objet RPC. Appelez get_result() sur l'élément RPC renvoyé pour forcer la requête à se terminer. Lorsque vous ajoutez des tâches de manière asynchrone dans une transaction, appelez get_result() sur l'élément RPC avant d'effectuer un commit de la transaction pour vous assurer que la requête est terminée.

Mettre des tâches en file d'attente dans des transactions Cloud Datastore

Vous pouvez placer une tâche en file d'attente dans le cadre d'une transaction Cloud Datastore, de telle sorte que la tâche n'est mise en file d'attente (et garantie d'être mise en file d'attente) que si la transaction est correctement validée. Les tâches ajoutées à une transaction sont considérées comme faisant partie de celle-ci et possèdent le même niveau d'isolation et de cohérence.

Une application ne peut pas insérer plus de cinq tâches transactionnelles dans des files d'attente de tâches au cours d'une même transaction. Les tâches transactionnelles ne doivent pas porter de noms spécifiés par l'utilisateur.

L'exemple de code suivant montre comment insérer des tâches transactionnelles dans une file d'attente d'envoi dans le cadre d'une transaction Cloud Datastore :

from google.appengine.api import taskqueue
from google.appengine.ext import ndb

@ndb.transactional
def do_something_in_transaction():
  taskqueue.add(url='/path/to/my/worker', transactional=True)
  #...

do_something_in_transaction()

Utiliser la bibliothèque de tâches différée au lieu d'un service de nœuds de calcul

La configuration d'un gestionnaire pour chaque tâche distincte (telle que décrite dans les sections précédentes) peut s'avérer fastidieuse, tout comme la sérialisation et la désérialisation d'arguments complexes, notamment si vous souhaitez que la file d'attente exécute de nombreuses tâches diverses, mais de faible taille. Le SDK Python comprend un package (google.appengine.ext.deferred) qui expose une API simple vous permettant de contourner le travail de configuration des gestionnaires de tâches dédiés, et de sérialiser et désérialiser vos paramètres.

Pour utiliser cette bibliothèque, vous devez ajouter le composant intégré deferred au fichier app.yaml. Pour plus d'informations, consultez la section Gestionnaires intégrés de la référence du fichier app.yaml.

Pour utiliser la bibliothèque deferred, il suffit de transmettre la fonction et ses arguments à la méthode deferred.defer() :

import logging

from google.appengine.ext import deferred

def do_something_expensive(a, b, c=None):
    logging.info("Doing something expensive!")
    # Do your work here

# Somewhere else
deferred.defer(do_something_expensive, "Hello, world!", 42, True)

La bibliothèque deferred regroupe l'appel de fonction et ses arguments, puis les ajoute à la file d'attente de tâches. Une fois la tâche exécutée, le package deferred exécute la fonction do_something_expensive("Hello, world!.", 42, True).

Pour en savoir plus sur l'utilisation de la bibliothèque deferred, reportez-vous à Exécuter des tâches en arrière-plan à l'aide de la bibliothèque différée.

Exécuter des tâches dans une application mutualisée

Par défaut, les files d'attente d'envoi utilisent l'espace de noms actuel tel qu'il est défini dans le gestionnaire d'espaces de noms au moment de la création de la tâche. Si votre application exploite une architecture mutualisée, consultez la section API Namespaces Python.

Étape suivante

Cette page vous a-t-elle été utile ? Évaluez-la :

Envoyer des commentaires concernant…

Environnement standard App Engine pour Python