Article / 20th Mar 2019

ASGI 3.0

As of today, the 20th March 2019, ASGI 3.0 is released, and it brings with it a major change to the protocol: the way in which apps are structured.

Previously, ASGI apps looked like this:

class Application:

    def __init__(self, scope):
        ...

    async def __call__(self, receive, send):
        ...

This was a decision I had made back in 2016 while implementing the first versions of Daphne, as it made applications have "instances" that were easier to track. However, as time as gone on, it's clear that this is not really needed - coroutines are trackable too - and so, the new ASGI 3.0 apps look like this:

async def application(scope, receive, send):
    ...

This is both much simpler for new users to understand, as well as being a much happier successor to WSGI and it's single-callable format. It's difficult to change a specification when it already has several established implementations, but the resulting 3.0 spec was actually requested by Tom Christie, and given that I had been regretting the double-callable style for a while, I thought it was the perfect time to see if it was possible.

Backwards Compatibility

Of course, the major concern I had going in was backwards compatibility. Nearly a decade of helping to maintain Django has kept this forefront in my mind, and if we were going to ask people to change how they wrote apps on the spec entirely we'd probably fracture a still-growing community.

I suspected from the outset we could find a compatible route, that allowed ASGI 2 apps to run under ASGI 3 in the same way we can also run WSGI, and we found one that seems to work flawlessly for this upgrade. Not only that, there's a reference implementation of how to detect which sort of ASGI an app is expecting as well as an adapter from 2 to 3.

Servers can literally add a single line to their application loading interface and get support for both versions, which means we can hopefully pull off a pretty seamless migration between the both of them.

The story is more complex for application frameworks, but we've had some input from some of the people maintaining those, and we're hopeful we can keep the migration pretty painless (as well as having the end result be significantly simpler apps).

There's also room for a 3-to-2 adapter if it's needed, but we didn't ship that in the main repo.

Next Steps

Now this is out of the door, the work to get support for it into ASGI servers is underway. After this, ASGI should be pretty stable - we've had a year or so of polish - and I need to see if I can find the time to start focusing on adapting Django to it directly.

There's also the potential of trying to revive the PEP process for it now that we have a replacement for the previous PEP process after Guido stepped down last year, but there's a lot of resistance around that, since the only reason to make it a PEP is because WSGI is one.

We're getting pretty good traction without it, anyway, and moving ASGI to have its own small site (asgi.readthedocs.io) has helped separate it from Django and Channels a bit. Just need to make sure we can keep moving forward and get more projects signing up!