web-dev-qa-db-fra.com

Comment associer le céleri à l'asyncio?

Comment créer un emballage qui donne aux tâches de céleri l'apparence suivante: asyncio.Task? Ou existe-t-il un meilleur moyen d’intégrer le céleri avec asyncio?

@asksol, créateur du céleri, a dit ceci: :

Il est assez courant d’utiliser Celery en tant que couche distribuée au-dessus d’infrastructures d’E/S asynchrones (astuce: acheminer des tâches liées à la CPU à un préposé à l’emploi du forfork signifie qu’elles ne bloqueront pas votre boucle d’événements.

Mais je n'ai trouvé aucun exemple de code spécifique au framework asyncio.

19
max

Cela sera possible à partir de la version 5.0 de Celery comme indiqué sur le site officiel:

http://docs.celeryproject.org/en/4.0/whatsnew-4.0.html#preface

  1. La prochaine version majeure de Celery ne supportera que Python 3.5, si nous prévoyons de tirer parti de la nouvelle bibliothèque asyncio.
  2. En abandonnant la prise en charge de Python 2, nous pourrons supprimer d’énormes quantités de code de compatibilité, et utiliser Python 3.5 nous permet de tirer parti des concepts de frappe, async/wait, asyncio et de concepts similaires.

_ {Ce qui précède a été cité à partir du lien précédent. _

La meilleure chose à faire est donc d’attendre que la version version 5.0 soit distribuée!

En attendant, bon codage :)

12
John Moutafis

Vous pouvez intégrer tout appel bloquant dans une tâche en utilisant run_in_executor comme décrit dans documentation , j'ai également ajouté dans l'exemple un timeout personnalisé :

def run_async_task(
    target,
    *args,
    timeout = 60,
    **keywords
) -> Future:
    loop = asyncio.get_event_loop()
    return asyncio.wait_for(
        loop.run_in_executor(
            executor,
            functools.partial(target, *args, **keywords)
        ),
        timeout=timeout,
        loop=loop
    )
loop = asyncio.get_event_loop()
async_result = loop.run_until_complete(
    run_async_task, your_task.delay, some_arg, some_karg="" 
)
result = loop.run_until_complete(
    run_async_task, async_result.result 
)
2
danius

La méthode la plus propre que j'ai trouvée consiste à envelopper la fonction async dans asgiref.sync.async_to_sync (from asgiref ):

from asgiref.sync import async_to_sync
from celery.task import periodic_task


async def return_hello():
    await sleep(1)
    return 'hello'


@periodic_task(
    run_every=2,
    name='return_hello',
)
def task_return_hello():
    async_to_sync(return_hello)()

J'ai tiré cet exemple d'un blog post j'ai écrit.

1
Franey