如果任务对象存储在实例变量中,Starlette+asyncio.create_task()不会记录错误

2024-05-19 00:44:09 发布

您现在位置:Python中文网/ 问答频道 /正文

好吧,这很奇怪,但这是-

import asyncio

from starlette.applications import Starlette


class MyTasks:
    def __init__(self):
        self.task = None

    async def main(self):
        self.task = asyncio.create_task(self.hello())

    async def hello(self):
        raise ValueError


async def main():
    await MyTasks().main()


app = Starlette(on_startup=[main])

$ uvicorn test:app
INFO:     Started server process [26622]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)

嗯,不ValueError这里


现在,删除MyTasks.main()中对self.task的赋值

    async def main(self):
        asyncio.create_task(self.hello())
    ...

$ uvicorn test:app
INFO:     Started server process [29083]
INFO:     Waiting for application startup.
ERROR:    Task exception was never retrieved
future: <Task finished name='Task-3' coro=<MyTasks.hello() done, defined at ./test.py:13> exception=ValueError()>
Traceback (most recent call last):
  File "./test.py", line 14, in hello
    raise ValueError
ValueError
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)

。。。瞧


这是怎么回事?这个分配是如何实现或破坏异常日志记录的


Tags: testselfinfoasyncioapphellotaskasync
2条回答

任务是future的子类,这意味着它具有结果的概念。对于任务,结果是它驱动的协同程序返回的值。如果协同程序引发异常,则异常将封装在任务对象中。正确编写的代码最终会等待任务或访问其结果,以便异常不会以静默方式传递

为了帮助调试忘记访问任务的代码,如果任务引发异常但从未等待,则任务的析构函数将记录错误。在运行析构函数之前,不能记录此错误,因为只要代码保持任务对象不变,它可能会在任何时候等待它。析构函数的运行点是Python能够可靠地“证明”任务未等待的第一个实例

但这种最后的日志记录不是您应该依赖的,它是在尽力而为的基础上提供的。例如,由于GC的原因,运行析构函数可能会被推迟。我希望将任务分配给其绑定方法由任务驱动的实例会使任务成为引用周期的一部分。这会将析构函数的运行推迟到完全GC,并且您不会看到日志

要解决这个问题,您应该在协同程序中捕获异常并自己记录它们,而不是允许它们传播,或者在代码中的某个点实际等待任务

对不起,这是个骗局

替换为asyncio.create_task()has been posted there的人数减少


这是使用替换后的输出create_task()

案例1:与await self.task

$ uvicorn test:app
INFO:     Started server process [33213]
INFO:     Waiting for application startup.
ERROR:    Traceback (most recent call last):
  File "/Users/dev/.virtualenvs/server-99338def/lib/python3.8/site-packages/starlette/routing.py", line 517, in lifespan
    await self.startup()
  File "/Users/dev/.virtualenvs/server-99338def/lib/python3.8/site-packages/starlette/routing.py", line 494, in startup
    await handler()
  File "./test.py", line 35, in main
    await MyTasks().main()
  File "./test.py", line 27, in main
    print(await self.task)
  File "./test.py", line 13, in wrapper
    return await task
  File "./test.py", line 30, in hello
    raise ValueError
ValueError

ERROR:    Application startup failed. Exiting.

案例2:没有await self.task

$ uvicorn test:app
INFO:     Started server process [32627]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
ERROR:    Exception in callback <function create_task.<locals>.on_done at 0x10c519550>
handle: <Handle create_task.<locals>.on_done created at /Users/dev/.virtualenvs/server-99338def/lib/python3.8/site-packages/uvicorn/main.py:382>
source_traceback: Object created at (most recent call last):
  File "/Users/dev/.virtualenvs/server-99338def/bin/uvicorn", line 8, in <module>
    sys.exit(main())
  File "/Users/dev/.virtualenvs/server-99338def/lib/python3.8/site-packages/click/core.py", line 764, in __call__
    return self.main(*args, **kwargs)
  File "/Users/dev/.virtualenvs/server-99338def/lib/python3.8/site-packages/click/core.py", line 717, in main
    rv = self.invoke(ctx)
  File "/Users/dev/.virtualenvs/server-99338def/lib/python3.8/site-packages/click/core.py", line 956, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/Users/dev/.virtualenvs/server-99338def/lib/python3.8/site-packages/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "/Users/dev/.virtualenvs/server-99338def/lib/python3.8/site-packages/uvicorn/main.py", line 331, in main
    run(**kwargs)
  File "/Users/dev/.virtualenvs/server-99338def/lib/python3.8/site-packages/uvicorn/main.py", line 354, in run
    server.run()
  File "/Users/dev/.virtualenvs/server-99338def/lib/python3.8/site-packages/uvicorn/main.py", line 382, in run
    loop.run_until_complete(self.serve(sockets=sockets))
Traceback (most recent call last):
  File "uvloop/cbhandles.pyx", line 70, in uvloop.loop.Handle._run
  File "./test.py", line 9, in on_done
    fut.result()
  File "./test.py", line 30, in hello
    raise ValueError
ValueError

相关问题 更多 >

    热门问题