web-dev-qa-db-ja.com

Celeryとasyncioを組み合わせる方法

セロリのタスクをasyncio.Taskのように見せるためのラッパーを作成するにはどうすればよいですか?または、Celeryをasyncioと統合するより良い方法はありますか?

セロリの作成者である@asksol これはこう言った

Celeryを非同期I/Oフレームワーク上の分散レイヤーとして使用することは非常に一般的です(ヒント:CPUにバインドされたタスクをpreforkワーカーにルーティングすると、イベントループがブロックされなくなります)。

しかし、asyncioフレームワーク専用のコード例を見つけることができませんでした。

23
max

公式サイトに記載されているCeleryバージョン5.0から可能になります。

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

  1. Celeryの次のメジャーバージョンは、Python 3.5のみをサポートします。これは、新しいasyncioライブラリを利用する予定でした。
  2. Python 2のサポートをドロップすると、大量の互換性コードを削除できます。また、Python 3.5を使用すると、async/await 、asyncio、および同様の概念には、古いバージョンに代わるものはありません。

上記は前のリンクから引用されています。

最善の方法は、バージョン5.0が配布されるのを待つことです!

それまでの間、ハッピーコーディング:)

16
John Moutafis

documentation で説明されているように、run_in_executorを使用してブロッキング呼び出しをタスクにラップできます。この例では、カスタム timeout も追加しました。

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 
)
3
danius

私がこれを行うために見つけた最もクリーンな方法は、async関数をasgiref.sync.async_to_syncでラップすることです( 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)()

ブログ投稿 からこの例を引き出しました。

1
Franey

この簡単な方法はうまくいきました:

import asyncio
from celery import Celery

app = Celery('tasks')

async def async_function(param1, param2):
    # more async stuff...
    pass

@app.task(name='tasks.task_name', queue='queue_name')
def task_name(param1, param2):
    asyncio.run(async_function(param1, param2))
0
juanra