简体   繁体   English

aiohttp:在执行“asyncio.Task.all_tasks()”时,从 aiojobs.spawn() 创建的任务不会出现在主循环中

[英]aiohttp: Tasks created from aiojobs.spawn() don't appear in main loop when doing `asyncio.Task.all_tasks()`

I am using asyncio.Task.all_tasks() to figure out which tasks to cancel & which should I wait for during shutdown.我正在使用asyncio.Task.all_tasks()来确定要取消哪些任务以及在关机期间应该等待哪些任务。

So it looks like this:所以它看起来像这样:

    web.run_app(web_app, port=PORT, handle_signals=True)

    # Then in case the app is stopped, we do cleanup
   loop.run_until_complete(wait_for_all_blocker_coroutines_to_finish())

This is the function that waits for tasks that need to be completed before shutting down:这是在关闭之前等待需要完成的任务的函数:

async def wait_for_all_blocker_coroutines_to_finish() -> None:
    started_time = datetime.now()
    all_tasks = asyncio.Task.all_tasks() - {asyncio.current_task()}
    # all_tasks doesn't contain any tasks that I created inside of the spawn() coroutine
    logging.debug(f"Total tasks unfinished: {len(all_tasks)}")
    loop = asyncio.get_event_loop()
    logging.debug(f"Checking in loop {loop._thread_id}")
    logging.debug(all_tasks)
    coroutines = list(filter(filter_tasks_with_meta, all_tasks))
    logging.debug(coroutines)
    total = len(coroutines)
    logging.debug(f"Waiting for all blocker coroutines to finish ({total} total)")
    await asyncio.gather(*coroutines, return_exceptions=True)
    duration = datetime.now() - started_time
    seconds = duration.total_seconds()
    logging.debug(f"Coroutines unblocked after {seconds} seconds")

Somewhere inside of spawn(coro) I do this:在 spawn(coro) 的某个地方,我这样做:

class TaskMeta(TypedDict):
    is_meta: bool
    blocker: bool


def name_for_task_with_meta(task_meta: TaskMeta) -> str:
    return json.dumps(task_meta)


def create_app_blocking_task(coro) -> asyncio.Task:
    # We differentiate between tasks that need to be waited for using TaskMeta that is then converted into json string and saved in the name parameter (later we filter tasks by name)
    name = name_for_task_with_meta(TaskMeta(is_meta=True, blocker=True))
    loop = asyncio.get_running_loop()
    task = loop.create_task(coro, name=name)
    logging.debug(f"Creating blocking task with meta={name}, loop_id={loop._thread_id}")
    return task

job = create_app_blocking_task(coro)

The tasks that I want to wait for are created inside aiojobs.spawn() .我要等待的任务是在aiojobs.spawn()中创建的。 When I do asyncio.Task.all_tasks() inside of the coroutine ran by aiojobs.spawn() , it displays the correct listing of tasks.当我在asyncio.Task.all_tasks()运行的协程中执行aiojobs.spawn()时,它会显示正确的任务列表。

However, my shutdown handler is outside of aiojobs.spawn() coroutine, and when I do asyncio.Task.all_tasks() , it doesn't return anything.但是,我的关闭处理程序在aiojobs.spawn()协程之外,当我执行asyncio.Task.all_tasks()时,它不会返回任何内容。 Zero running tasks, even though they are actually running.零运行任务,即使它们实际上正在运行。

From what I understand, asyncio.Task.all_tasks() returns all running tasks inside of the current asyncio loop.据我了解, asyncio.Task.all_tasks()返回当前 asyncio 循环内所有正在运行的任务。 Could it be that spawn() creates a separate loop and thus tasks from there don't appear in the main loop?可能是spawn()创建了一个单独的循环,因此那里的任务不会出现在主循环中吗? If so, how can I prevent this?如果是这样,我该如何防止这种情况? Or can I get all loops and then get all tasks from each loop?或者我可以获取所有循环,然后从每个循环中获取所有任务吗? Or do graceful shutdown for spawn() separately?或者单独为 spawn() 优雅地关闭?

EDIT: So I figured out that these tasks get cancelled when I stop the application.编辑:所以我发现当我停止应用程序时这些任务会被取消。 My question now is: How do I prevent that?我现在的问题是:如何防止这种情况发生?

So the problem here was that aiohttp cancelled tasks before my shutdown handler could process them.所以这里的问题是 aiohttp 在我的关闭处理程序可以处理它们之前取消了任务。 The solution I used was to process tasks inside a on_shutdown handler.我使用的解决方案是在 on_shutdown 处理程序中处理任务。

    web_app = web.Application(client_max_size=1024 * 1024 * 40)
    web_app.on_shutdown.append(on_shutdown)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM