# バックグラウンドタスク
# Tasksを作成
非同期Pythonでtasks (opens new window)を使用することは、望ましいことが多く、非常に便利です。Sanicは、現在実行中の**ループにタスクを追加する便利な方法を提供します。これはasyncio.create_task
。'App'ループの実行前にタスクを追加する方法については、次のセクションを参照してください。
async def notify_server_started_after_five_seconds():
await asyncio.sleep(5)
print('Server successfully started!')
app.add_task(notify_server_started_after_five_seconds())
Sanicは自動的にアプリを注入し、タスクへの引数として渡す。
async def auto_inject(app):
await asyncio.sleep(5)
print(app.name)
app.add_task(auto_inject)
または、app
引数を明示的に渡すこともできます。
async def explicit_inject(app):
await asyncio.sleep(5)
print(app.name)
app.add_task(explicit_inject(app))
# app.run
の前にタスクを追加します
Appを実行する前にバックグラウンドタスクを追加することができます。app.run
の前に置きます。Appが実行される前にタスクを追加するには、コルーチンオブジェクト(つまり、。async
callable)を渡さずに、単に呼び出し可能オブジェクトを渡すことをお勧めします。Sanicは各ワーカーにコルーチンオブジェクトを作成します**.注:追加されるタスクはbefore_server_start
ジョブとして実行されるため、すべてのワーカーで実行されます (メインプロセスでは実行されません) 。これには特定の結果が伴います。詳細については、この問題 (opens new window) の このコメント (opens new window) を参照してください。
メイン・プロセスに作業を追加するには、@app.main_process_start
。注意:この作業が完了するまで、就業者は開始しません。
app.run
の前にタスクを追加する例
async def slow_work(...):
...
app = Sanic(...)
app.add_task(slow_work) # Note: we are passing the callable and not coroutine object `slow_work(...)`
app.run(...)
TIP
上記のslow_work
にパラメータを渡すには、functools.partial
を使用します。
# Named tasks
NEW in v21.12
Python 3.8以上でのみサポートされます
タスクを作成するときに、name
を指定することで、Sanicにそのタスクを追跡するように依頼することができます。
app.add_task(slow_work, name="slow_task")
これで、アプリケーションのどこからでも get_task
を使って、そのタスクのインスタンスを取得できるようになりました。
task = app.get_task("slow_task")
そのタスクをキャンセルする必要がある場合は、 cancel_task
を使って行うことができます。必ず await
してください。
await app.cancel_task("slow_task")
登録されたすべてのタスクは app.tasks
プロパティで確認することができます。キャンセルされたタスクが一杯になるのを防ぐために、app.purge_tasks
を実行して、完了したタスクやキャンセルされたタスクを消去するとよいでしょう。
app.purge_tasks()
このパターンは、特に websocket
で有効です:
async def receiver(ws):
while True:
message = await ws.recv()
if not message:
break
print(f"Received: {message}")
@app.websocket("/feed")
async def feed(request, ws):
task_name = f"receiver:{request.id}"
request.app.add_task(receiver(ws), name=task_name)
try:
while True:
await request.app.event("my.custom.event")
await ws.send("A message")
finally:
# When the websocket closes, let's cleanup the task
await request.app.cancel_task(task_name)
request.app.purge_tasks()