MagicStack / MagicStack/uvloop
Application hanging after KeyboardInterrupt
未关闭
还没有人认领这个 Issue。
- 主要语言
- Cython
- 星标
- 11.9k
- 派生
- 616
- PR 合并指标
- 30 天内没有已合并 PR
描述
- uvloop version: 0.14.0
- Python version: 3.7.4
- Platform: Manjaro
- Can you reproduce the bug with
PYTHONASYNCIODEBUGin env?: Yes - Does uvloop behave differently from vanilla asyncio? How?: With vanilla, the application terminates gracefully upon reception of a keyboard interrupt. If I use
uvloop, I get a runtime warning and the application hangs until I run akill -9on the process id.
Snippet: issue.py
import asyncio
from asyncio import AbstractEventLoop
import os
from typing import Union, Type
import uvloop # type: ignore
from aiohttp import web
import signal
import aiologger
logger = aiologger.Logger.with_default_handlers()
async def handle_exception(loop: AbstractEventLoop, context):
# context["message"] will always be there; but context["exception"] may not
msg = context.get("exception", context["message"])
await logger.error(f"Caught exception: {msg}")
await logger.info("Shutting down...")
asyncio.create_task(shutdown(loop))
async def shutdown(loop: AbstractEventLoop, signal=None):
"""Cleanup tasks tied to the service's shutdown."""
if signal:
await logger.info(f"Received exit signal {signal.name}...")
tasks = [t for t in asyncio.all_tasks() if t is not asyncio.current_task()]
[task.cancel() for task in tasks]
await logger.info(f"Cancelling {len(tasks)} outstanding tasks")
await asyncio.gather(*tasks, return_exceptions=True)
loop.stop()
async def start(
app: web.Application, host: str, port: Union[str, int]
) -> web.AppRunner:
"""Start the server"""
runner = web.AppRunner(app)
await runner.setup()
server = web.TCPSite(runner, host, int(port))
await server.start()
return runner
def main() -> None:
"""Entrypoint"""
host = os.environ.get("HOST", "localhost")
port = os.environ.get("PORT", 8000)
app = web.Application()
loop = asyncio.get_event_loop()
signals = (signal.SIGHUP, signal.SIGTERM, signal.SIGINT)
for s in signals:
loop.add_signal_handler(
s, lambda s=s: asyncio.create_task(shutdown(loop, signal=s))
)
loop.set_exception_handler(handle_exception)
print(
f"======== Running on http://{host}:{port} ========\n" "(Press CTRL+C to quit)"
)
try:
runner = loop.run_until_complete(start(app, host, port))
loop.run_forever()
finally:
loop.run_until_complete(runner.cleanup())
loop.close()
if __name__ == "__main__":
uvloop.install()
main()
Run the file:
python issue.py
Then hit Ctrl+c on keyboard, output:
======== Running on http://0.0.0.0:8000 ========
(Press CTRL+C to quit)
^Cissue.py:70: RuntimeWarning: coroutine 'handle_exception' was never awaited
Coroutine created at (most recent call last)
File "issue.py", line 78, in <module>
main()
File "issue.py", line 70, in main
loop.run_forever()
loop.run_forever()
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
Which hangs until running kill -9 <pid>
If you comment out uvloop.install() and follow the same steps, the program terminates as expected. Output:
======== Running on http://0.0.0.0:8000 ========
(Press CTRL+C to quit)
^CReceived exit signal SIGINT...
Cancelling 0 outstanding tasks
贡献指南
这个仓库没有索引到贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
调研方向
首先,在启用 PYTHONASYNCIODEBUG 的情况下,使用 uvloop 0.14.0 和 Python 3.7.4 运行 issue.py,然后将其对 Ctrl+C 的行为与 vanilla asyncio 进行比较。调查片段中所示的事件循环异常处理和信号关闭路径。完成的标准是:KeyboardInterrupt 能触发正常清理,且不会出现未等待 coroutine 的警告或进程挂起。
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- python
- 领域
- backend
- Issue 类型
- 缺陷
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 活跃度
- 停滞
- 描述清晰度
- 基本清楚
- 新手友好度
- 38/100