13

I have a simple API-based web application written in Django 3. In the Django documentation there is a page about ASGI servers, and two options are mentioned: Daphne and Uvicorn. Unfortunately, they do not provide any description about the benefits regarding a particular choice, so I am confused when it comes to select one of them.

What are, if any, differences for writing a Django application around the two and would there be any performance or stability issues to be aware of?

Basically, is there a big difference to use Uvicorn instead of Daphne? My server is running on Ubuntu, if that matters.

Kevin
  • 1,646
  • 1
  • 17
  • 23
rafaljusiak
  • 497
  • 3
  • 14
  • Why do you want to use an ASGI server? Are you using async code anywhere? – Tom Carrick May 09 '20 at 17:27
  • 2
    @TomCarrick I want to start use in some parts, mainly will try to speed-up some operations with data processing. Also I thought that this could affect the overall server performance when I swap the gunicorn for something else – rafaljusiak May 09 '20 at 17:34
  • [Django Channels](https://channels.readthedocs.io) is gives a framework to work with async in Django. I have some long running jobs that I want to put websockets in front of. A pattern seen, is to have a separate async socket server putting messages into a broker, then a Django service subscribes to it. Channels is be a reason for Uvicorn vs Daphne. For async coroutine performance for a regular Django app, [gunicorn can run workers in greenlets](https://docs.gunicorn.org/en/stable/design.html#async-workers) instead of threads by leveraging eventlet or gevent. – Kevin Jul 08 '20 at 20:16
  • `Hypercorn` is mentioned too now. – Mahmoud Adel Apr 20 '21 at 00:09

1 Answers1

12

Simple Answer: Since you've used gunicorn before and you're familiar with it, go with uvicorn, specially since it should be used as a gunicorn worker in production. If you have no experience with it, then I would suggest daphne. Both will do the job on a simple project, and the performance seems to be equal.


Explanation:

ASGI is a rather new technology, and so is python's async/await in comparison to most other design-changing elements in the language. Both uvicorn, daphne and hypercorn are also in active development, so there can't be any "fair" benchmarking of these libraries. So when it comes to choosing what you want, you mostly have to take their word for it when they say for example; they aim for being fast, simple to use, lightweight or whatever.

All that being said, I can still share my experience with Uvicorn and Daphne:

Daphne is definitely the bulkier project, it has a lot of dependencies that are not entirely used in every project. They sure have done their best covering lots of features, and since they are also part of the Django team, you should expect a better long term compatibility with Django. Getting started with Daphne can be intimidating though.

Uvicorn is the light-weight one, you can even read the code of the whole library and kinda understand how the cogs turn inside. Since I've mostly used Uvicorn, I know it has some missing features and bugs that are rather expected to work out of the box, If you want a custom behavior from your ASGI server, tampering with Uvicorn is easier than the alternative. My favorite part about Uvicorn, is that it is not even a process manager, and is designed to work as gunicorn's worker for production.

Side note: hooking into Uvicorn is not actually intended or easy. It's not generally good practice to do this, but given that after 18 hours of searching for an alternative (I personally wanted to catch and handle SIGTERM for graceful shutdown, but the normal methods didn't work since everything is in a async loop), I couldn't find any better ways. So I will shamelessly put a piece of code that will grant you the elusive "server" instance. From there, thread carefully. (no pun intended)

import inspect #Might not be future proof! Use with care
from uvicorn import Server as UvicornServer
server = next( server for frameinf in inspect.stack() if 'server' in frameinf[0].f_locals and isinstance(server:=frameinf[0].f_locals['server'], UvicornServer) )

Another Sidenote: If you actually choose to go with Uvicorn, and you're using django with channels, you might want to remove "daphne" first, since it's a rather unused dependency of channels.

user650881
  • 1,832
  • 17
  • 23
aliqandil
  • 1,223
  • 14
  • 26
  • well, I need to say that I'm trying to have the development environment and the staging/production as similar as possible. So I'm using Daphne in delelopment too. No issues so far... BUT it doesn't support autoreload and [it will never be implemented](https://github.com/django/daphne/issues/9). Both hypercorn and uvicorn do. – Paolo Apr 25 '21 at 13:55
  • ok I should further add that hypercorn supports HTTP2, uvicorn currently not (Apr, 2021). – Paolo Apr 25 '21 at 14:10