[Fixed]-Django + Uvicorn

8👍

No, lifespan protocol doesn’t work with Django 3.0.

See this ticket: https://code.djangoproject.com/ticket/31508

2👍

Here’s the initial setup I used with django 3.1 / 3.2

EDIT: some rough performance benchmarks: https://github.com/allen-munsch/benchmark-django-fastapi

old version

your_django/old_wsgi.py:

import os

from django.core.wsgi import get_wsgi_application
from dj_static import Cling

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "your_django.settings")

application = Cling(get_wsgi_application())

Previously run as:

newrelic-admin run-program gunicorn your_django.old_wsgi \
-k eventlet --log-file - --timeout 60

new version

your_django/asgi.py:

import os

from django.core.asgi import get_asgi_application
from django.contrib.staticfiles.handlers import ASGIStaticFilesHandler

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pm.settings")

application = ASGIStaticFilesHandler(
    get_asgi_application()
)

And to run

gunicorn your_django.asgi --log-level=debug -k uvicorn.workers.UvicornWorker \
--log-file - --timeout 60

# OR for local dev

uvicorn --reload your_django.asgi

related:

2👍

As @KubaMisiorny pointed out. Django does not support Lifespan Protocol.

If you would like to disable this protocol, you have a couple of options depending on what your setup is.

Running uvicorn

Pass --lifespan off option.

uvicorn --lifespan off

Running gunicorn with uvicorn.workers.UvicornWorker

You will need to pass config arguments by creating a subclass of the worker class

Create uvicorn_worker.py

from uvicorn.workers import UvicornWorker as BaseUvicornWorker


# Django does not support Lifespan Protocol
# https://asgi.readthedocs.io/en/latest/specs/lifespan.html
# https://github.com/django/django/pull/13636
# https://code.djangoproject.com/ticket/31508
# Using uvicorn.workers.UvicornWorker throws INFO warning:
#   "ASGI 'lifespan' protocol appears unsupported."
# To avoid that we need to disable 'lifespan' in the worker
class UvicornWorker(BaseUvicornWorker):
    CONFIG_KWARGS = {"lifespan": "off"}

In gunicorn.conf.py

# https://www.uvicorn.org/deployment/#gunicorn
# using custom one to disable Lifespan Protocol
# needs to be passed by string https://github.com/benoitc/gunicorn/issues/1539
worker_class = "uvicorn_worker.UvicornWorker"

Leave a comment