28

I have an asynchronous code running on fastapi & aiofiles i'm trying to load and save my info from a .json file but every time I shut down the program, it save only the keys of the dict and showing me "ASGI 'lifespan' protocol appears unsupported" massage

this is my turn on/off part:

@app.on_event("startup")
async def startup_event():
    global beers
    try:
        async with aiofiles.open("data.json", mode='r+', json=True) as file:
            beers = await file.read()
    except:
        beers = {}


@app.on_event("shutdown")
async def on_exit_app():
    async with aiofiles.open("data.json", "w+") as outfile:
        await outfile.write(beers)

any ideas where is the problem?

M. Volf
  • 1,259
  • 11
  • 29
yuval hayun
  • 281
  • 1
  • 3
  • 4
  • I got the same message, and exception if I started `uvicorn` with the option `--lifespan on`. Then I found that the lifespan in `uvicorn` requires `FastAPI` instance to be assigned to a module variable as soon as the module is initially loaded by `uvicorn`, but have not really figured out why `uvicorn` works that way. – Ham Aug 24 '23 at 04:21

3 Answers3

33

This 99% means that something in the on_event("shutdown") function throws an error that isn't caught by the server (FastAPI/Starlette), and the app crashes, instead of ending properly. This leads uvicorn to believe that the server doesn't support the livespan part of the ASGI protocol.

If you run uvicorn with additional option --lifespan on, the error will be shown and you can debug it.

See Starlette bug report.

M. Volf
  • 1,259
  • 11
  • 29
4

It is just an assertion you can omit that, as far as I understand you are using Uvicorn as an HTTP server, since FastAPI is built top on an ASGI framework and Uvicorn is an ASGI HTTP server, there are some protocols on it. ASGI protocol has support for http, websocket.

Uvicorn sets lifespan's value to auto and the assertion comes from there.

if self.config.lifespan == "auto":
    msg = "ASGI 'lifespan' protocol appears unsupported."

But you can use --lifespan on to fix that.

Yagiz Degirmenci
  • 16,595
  • 7
  • 65
  • 85
2

I had the same error in a Django application. When the server starts, it seems to work well, but the message [INFO] ASGI 'lifespan' protocol appears unsupported appears.

(authentication-py3.11) ml@192 authentication % python -m gunicorn "authentication.asgi:application"
[2023-04-12 10:07:28 -0300] [2900] [INFO] Starting gunicorn 20.1.0
[2023-04-12 10:07:28 -0300] [2900] [INFO] Listening at: http://0.0.0.0:8000 (2900)
[2023-04-12 10:07:28 -0300] [2900] [INFO] Using worker: uvicorn.workers.UvicornWorker
[2023-04-12 10:07:28 -0300] [2902] [INFO] Booting worker with pid: 2902
[2023-04-12 13:07:29 +0000] [2902] [INFO] Started server process [2902]
[2023-04-12 13:07:29 +0000] [2902] [INFO] Waiting for application startup.
[2023-04-12 13:07:29 +0000] [2902] [INFO] ASGI 'lifespan' protocol appears unsupported.
[2023-04-12 13:07:29 +0000] [2902] [INFO] Application startup complete.

Following a solution in this issue, I created a custom uvicorn worker disabling the lifespan protocol.

workers.py

from typing import Any, Dict

from uvicorn.workers import UvicornWorker as BaseUvicornWorker


class UvicornWorker(BaseUvicornWorker):
    CONFIG_KWARGS: Dict[str, Any] = {"loop": "auto", "http": "auto", "lifespan": "off"}

gunicorn.conf.py

from myapp import settings

port = int(settings.APPLICATION_PORT)
bind = f"0.0.0.0:{port}"
workers = int(settings.GUNICORN_WORKERS)
worker_class = "myapp.workers.UvicornWorker"
accesslog = "-"
mathias.lantean
  • 541
  • 4
  • 10