Adding ASGI support to runserver

This thread is continuing conversations started here.

I have a little asgi runserver django app that adds asgi support to runserver.

I also have a pr to django to add get_response_async to make sure static files work with the ASGIStaticFilesHandler

These are 4 options I have thought of so far for a path to asgi support with runserver:

  1. Update runserver in django in a way that keeps the daphne import optional.
  2. Add daphne as a dependency to django and update runserver.
  3. Maintain a separate django app that holds the command that integrates daphne with runserver. Reference the app in asgi section of the django documentation.
  4. Add the commands to the daphne repository, perhaps allowing us to add daphne as an installed app so the command is discovered, and reference this in the asgi section of the django documentation.

Right now I have some code as option (3). I feel like option (4) could make sense as well. This code is specifically tied to daphne. Since daphne is already a project under the django organization, maybe it’s ok to put a command in that package and add as a django app. It’s one fewer separate dependency to install. (1) and (2) would probably involve lots of discussion.

If you’d like to help on this task, you could make a pr to asgi-runserver app to help refactor code paths between asgi/wsgi, unless I get to it first :slight_smile: . Alternatively, you could try out option (4) against daphe and see what it’s like.

1 Like

I think the right path for Django in general is option (1), honestly, which is to have the runserver command be ready to do this (behind an --async flag), but the import is delayed until you ask for it, and then it tries, with a nice warning message if it fails.

I will add to keep daphene as an optional dependency. I may prefer to run under uvicorn on production and don’t want daphene around there.

ticket and pr created. Let me know if you have any feedback!

Grrr. I’m not immediately sure that bundling the dependency on Daphne is the way to go.

Yes, if runserver just worked would be good, but the draft PR is quite big, and doesn’t allow for other ASGI servers at all.

What’s the alternative? Install channels and add to INSTALLED_APPS. This is Option 3. This would allow an uvicorn-runserver option and so on. It’s not as neat but it might be a lot cleaner. It’d be more flexible too. :grimacing:

Issue: https://code.djangoproject.com/ticket/31626
Draft PR: https://github.com/django/django/pull/12969/files

Grrr. I’m not immediately sure that bundling the dependency on Daphne is the way to go.

I don’t love it either

Yes, if runserver just worked would be good, but the draft PR is quite big, and doesn’t allow for other ASGI servers at all.

The pr begins to address this with a run_asgi method that could be implemented by an alternative package, while the run_wsgi path would stay the same, with as much of the code paths shared. It’s not perfect right now. For example, it would take some work to use uvicorn with its built in hot reloading instead of the django hot reloading.

What’s the alternative? Install channels and add to INSTALLED_APPS . This is Option 3. This would allow an uvicorn-runserver option and so on. It’s not as neat but it might be a lot cleaner. It’d be more flexible too. :grimacing:

It’s funny I never even considered installing channels to solve this problem. I’m not sure if that’s a good or bad thing. This may be naivety, but a suggestion to install channels to in order to do local development blurs the line for me on what native asgi support in core django means. I look at channels as a solution for distributed messaging (eg, websockets specifically). In the case of just wanting to run async python on an http server, where does channels fall into the ecosystem?

To me, django is opinionated and just works. At a high level, I had no issues running uvicorn myproject.asgi:application for local development, but then I realized that I wasn’t getting hot reloading. That’s easy enough to fix, and then I realized my migrations were out of date, also easy. Then I noticed I wasn’t seeing system checks. These are all small things but they normally just work and they don’t for asgi. It was enough for me to think “maybe I could make this better for the next person who tries to run django with asgi”.

Yes. And these are all good points. But ASGI support is new and immature. It’s developing rapidly, but it’s not clear that we have to bundle everything into Django itself at the first pass. Relying on twisted (at this stage) is a big ask, I think.

What are we expecting? That most folks will keep using WSGI, and add maybe a sprinkling of async def views. Then that a % will want to run under ASGI. For those, at this stage, I’m not sure a “pip install and then use runserver” is too much to ask.

(Note “not sure”.)

What are we expecting? That most folks will keep using WSGI, and add maybe a sprinkling of async def views. Then that a % will want to run under ASGI. For those, at this stage, I’m not sure a “pip install and then use runserver” is too much to ask.

  1. That’s a great question. For non greenfield projects, do we think that some people will sidecar their asgi application alongside wsgi due to compatibility/performance reasons? Or will it be all wsgi or all asgi?

  2. Despite me making the pr, I agree with you. I don’t think it’s too much to ask either which is why i started there. I can see both sides. Maybe @andrewgodwin wants to chime in here. If we do choose the separate installable package route, I think we should add something in the docs. I’ll also defer to y’all as to whether it makes sense to just use channels, as it exists and would work, or if we want a separate package to handle it.

Yes, we should definitely doc something here for 3.1.