uvicorn: Shutdown process is broken in 0.15

Checklist

  • The bug is reproducible against the latest release and/or master.
  • There are no similar issues or pull requests to fix it yet.

Describe the bug

My FastAPI ASGI server cannot shutdown properly with uvicorn==0.15 while it can with 0.14

To reproduce

Setup minimal FastAPI app and add some functions with logs(prints) to shutdown event

Expected behavior

You see all logs(prints) from functions on shutdown

Actual behavior

Get ASGI 'lifespan' protocol appears unsupported. without --lifespan on Get error trace with --lifespan on

Debugging material

uvicorn scheduler.main:app --host=0.0.0.0 --port ${WEB_PORT:-8000} --reload --lifespan on INFO: Will watch for changes in these directories: [‘/home/dmytro/storage/chimplie/projects/raok-main/raok-scheduler’] INFO: Uvicorn running on http://0.0.0.0:8004 (Press CTRL+C to quit) INFO: Started reloader process [177653] using statreload INFO: Started server process [177655] INFO: Waiting for application startup. INFO: Tortoise-ORM started, {‘default’: <tortoise.backends.asyncpg.client.AsyncpgDBClient object at 0x7f63d4a10e50>}, {‘models’: {‘Task’: <class ‘scheduler.models.task.Task’>, ‘Aerich’: <class ‘aerich.models.Aerich’>}} INFO: Application startup complete. ^CINFO: Shutting down INFO: Finished server process [177655] ERROR: Exception in ‘lifespan’ protocol Traceback (most recent call last): File “/home/dmytro/.local/share/virtualenvs/raok-scheduler-hpGGYNLi/lib/python3.8/site-packages/uvicorn/lifespan/on.py”, line 84, in main await app(scope, self.receive, self.send) File “/home/dmytro/.local/share/virtualenvs/raok-scheduler-hpGGYNLi/lib/python3.8/site-packages/uvicorn/middleware/proxy_headers.py”, line 75, in call return await self.app(scope, receive, send) File “/home/dmytro/.local/share/virtualenvs/raok-scheduler-hpGGYNLi/lib/python3.8/site-packages/fastapi/applications.py”, line 199, in call await super().call(scope, receive, send) File “/home/dmytro/.local/share/virtualenvs/raok-scheduler-hpGGYNLi/lib/python3.8/site-packages/starlette/applications.py”, line 112, in call await self.middleware_stack(scope, receive, send) File “/home/dmytro/.local/share/virtualenvs/raok-scheduler-hpGGYNLi/lib/python3.8/site-packages/starlette/middleware/errors.py”, line 146, in call await self.app(scope, receive, send) File “/home/dmytro/.local/share/virtualenvs/raok-scheduler-hpGGYNLi/lib/python3.8/site-packages/starlette/middleware/cors.py”, line 70, in call await self.app(scope, receive, send) File “/home/dmytro/.local/share/virtualenvs/raok-scheduler-hpGGYNLi/lib/python3.8/site-packages/starlette/exceptions.py”, line 58, in call await self.app(scope, receive, send) File “/home/dmytro/.local/share/virtualenvs/raok-scheduler-hpGGYNLi/lib/python3.8/site-packages/starlette/routing.py”, line 569, in call await self.lifespan(scope, receive, send) File “/home/dmytro/.local/share/virtualenvs/raok-scheduler-hpGGYNLi/lib/python3.8/site-packages/starlette/routing.py”, line 544, in lifespan await receive() File “/home/dmytro/.local/share/virtualenvs/raok-scheduler-hpGGYNLi/lib/python3.8/site-packages/uvicorn/lifespan/on.py”, line 135, in receive return await self.receive_queue.get() File “/usr/lib64/python3.8/asyncio/queues.py”, line 163, in get await getter asyncio.exceptions.CancelledError INFO: Stopping reloader process [177653]

image

Environment

  • Fedora 34 / Python 3.8 / Uvicorn version: 0.15 - bug, 0.14 - ok
  • command to run: uvicorn main:app --host=0.0.0.0 --port 8000 --reload

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 8
  • Comments: 24 (9 by maintainers)

Commits related to this issue

Most upvoted comments

I’m having the exactly same issue!! Here’s the code https://github.com/igormcsouza/kitty-api/blob/master/api/__init__.py

I downgrade to 0.14 just to avoid error

Even though the problem persist! I tried once more yesterday! That error at the end causes issues on my routine! I will keep on 0.14 until it is fixed!

I get the same error with Starlette 0.16.0 when I send a SIGINT:

[2021-08-19 11:01:19,614][25024] INFO:     Uvicorn running on http://0.0.0.0:5000 (Press CTRL+C to quit)
[2021-08-19 11:01:23,189][25024] ERROR:    Traceback (most recent call last):
  File "c:\Users\...\.venv\lib\site-packages\starlette\routing.py", line 624, in lifespan
    await receive()
  File "c:\Users\...\.venv\lib\site-packages\uvicorn\lifespan\on.py", line 135, in receive
    return await self.receive_queue.get()
  File "C:\Users\...\python\current\lib\asyncio\queues.py", line 166, in get
    await getter
asyncio.exceptions.CancelledError

I never had to create a lifespan function in previous versions, but I found that the error disappears if I bootstrap Starlette like so:

async def _lifespan(app):
  import asyncio
  try:
    yield
  except asyncio.exceptions.CancelledError:
    pass
server_app = Starlette(routes=routes, lifespan=_lifespan)

Ok… It was quite fast to find it 😅

The problem is that on reload mode, we terminate the process on the shutdown(): https://github.com/encode/uvicorn/commit/de53c2366f1df9f55ac88d8bde67cfd314d2d98e