MagicStack / MagicStack/uvloop
Application hanging after KeyboardInterrupt
Nobody has claimed this yet.
- Dominant language
- Cython
- Stars
- 11.9k
- Forks
- 616
- PR merge metrics
- No merged PRs in 30d
Description
- 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
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the reported issue.py with uvloop 0.14.0, Python 3.7.4, and PYTHONASYNCIODEBUG enabled, then compare its Ctrl+C behavior with vanilla asyncio. Investigate the event-loop exception handling and signal shutdown path shown in the snippet. Done means KeyboardInterrupt triggers graceful cleanup without the unawaited-coroutine warning or a hanging process.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100