web-dev-qa-db-fra.com

Comment utiliser le décorateur @shared_task pour les tâches basées sur la classe

Comme vu sur le documentation le @shared_task le décorateur vous permet de créer des tâches sans avoir d'instance d'application concrète. Les exemples donnés montrent comment décorer une tâche basée sur une fonction.

Comment décorer une tâche basée sur la classe?

30
Juan Riaza

Citant Ask à partir du fil d'utilisateurs de céleri où il a expliqué la différence entre @task et @shared_task. Voici le lien vers le fil

TL; DR; @shared_task créera l'instance indépendante de la tâche pour chaque application, rendant la tâche réutilisable.

Il y a une différence entre @task (shared = True) et @shared_task

Le décorateur de tâches partagera les tâches entre les applications par défaut de sorte que si vous le faites:

app1 = Celery() 
@app1.task 
def test(): 
    pass 

app2 = Celery() 

la tâche de test sera enregistrée dans les deux applications:

 assert app1.tasks[test.name] 
 assert app2.tasks[test.name] 

Cependant, le nom "test" fera toujours référence à l'instance liée à l'application "app1", elle sera donc configurée à l'aide de la configuration de app1:

assert test.app is app1 

Le décorateur @shared_task renvoie un proxy qui utilise toujours l'instance de tâche dans le current_app:

app1 = Celery() 

@shared_task 
def test(): 
    pass 
assert test.app is app1 


app2 = Celery() 
assert test.app is app2 

Cela rend le décorateur @shared_task utile pour les bibliothèques et les applications réutilisables, car ils n'auront pas accès à l'application de l'utilisateur.

De plus, l'exemple de projet Django par défaut définit l'instance d'application dans le cadre du projet Django:

depuis l'application d'importation proj.celry

et cela n'a aucun sens pour qu'une application réutilisable Django dépende du module de projet, car elle ne serait plus réutilisable.

18
Saurabh

La documentation à laquelle vous avez lié dit:

Le décorateur @shared_task vous permet de créer des tâches sans avoir d'instance d'application concrète:

Pour autant que je sache, la documentation est trompeuse et devrait indiquer:

Le décorateur @shared_task vous permet de créer des tâches qui peuvent être utilisées par n'importe quelle application.

En fait, toute tâche doit être attachée à une instance d'application. Mes preuves proviennent du fichier source de céleri celery/app/builtins.py:

def shared_task(constructor):
    """Decorator that specifies a function that generates a built-in task.

    The function will then be called for every new app instance created
    (lazily, so more exactly when the task registry for that app is needed).

    The function must take a single ``app`` argument.
    """
    _shared_tasks.add(constructor)
    return constructor

Donc, il ressemble comme vous pouvez utiliser ce décorateur pour créer une tâche sans avoir d'instance d'application concrète, mais en fait la fonction décorée DOIT prendre un argument d'application - comme le dit le commentaire source.

La fonction suivante suit:

def load_shared_tasks(app):
    """Create built-in tasks for an app instance."""
    constructors = set(_shared_tasks)
    for constructor in constructors:
        constructor(app)

Vous pouvez confirmer ici que chaque fonction décorée par @shared_taskswill sera invoqué avec un argument app.

9
jdhildeb