The shutdown event from the ASGI lifespan specification (https://asgi.readthedocs.io/en/latest/specs/lifespan.html) does not seem to be sent properly.
Steps to reproduce: Put the following code into test.py:
async def app(scope, receive, send):
if scope['type'] == 'lifespan':
while True:
message = await receive()
print(message)
else:
pass # Handle other types
and run with granian --interface asgi test.py:app, then interrupt the process with Ctrl+C. This will print
[INFO] Starting granian (main PID: 35828)
[INFO] Listening at: http://127.0.0.1:8000
[INFO] Spawning worker-1 with PID: 37184
{'type': 'lifespan.startup'}
[INFO] Shutting down granian
but there should be an additional {'type': 'lifespan.shutdown'} after pressing Ctrl+C (tested on Windows with python 3.14.0 and granian 2.6.0).
I don't have a good understanding of the code base, but the issue might be that the line
|
loop.run_until_complete(lifespan_handler.shutdown()) |
is not inside a finally block, and so will not be called if KeyboardInterrupt (or any other exception) is raised inside serve().
The shutdown event from the ASGI lifespan specification (https://asgi.readthedocs.io/en/latest/specs/lifespan.html) does not seem to be sent properly.
Steps to reproduce: Put the following code into
test.py:and run with
granian --interface asgi test.py:app, then interrupt the process with Ctrl+C. This will printbut there should be an additional
{'type': 'lifespan.shutdown'}after pressing Ctrl+C (tested on Windows with python 3.14.0 and granian 2.6.0).I don't have a good understanding of the code base, but the issue might be that the line
granian/granian/server/mp.py
Line 197 in 189f1be
is not inside a finally block, and so will not be called if KeyboardInterrupt (or any other exception) is raised inside serve().