2.1.0 Release Notes

Channels 2.1 brings a few new major changes to Channels as well as some more minor fixes. In addition, if you’ve not yet seen it, we now have a long-form tutorial to better introduce some of the concepts and sync versus async styles of coding.

Major Changes

Async HTTP Consumer

There is a new native-async HTTP consumer class, channels.generic.http.AsyncHttpConsumer. This allows much easier writing of long-poll endpoints or other long-lived HTTP connection handling that benefits from native async support.

You can read more about it in the Consumers documentation.

WebSocket Consumers

These consumer classes now all have built-in group join and leave functionality, which will make a consumer join all group names that are in the iterable groups on the consumer class (this can be a static list or a @property method).

In addition, the accept methods on both variants now take an optional subprotocol argument, which will be sent back to the WebSocket client as the subprotocol the server has selected. The client’s advertised subprotocols can, as always, be found in the scope as scope["subprotocols"].

Nested URL Routing

URLRouter instances can now be nested inside each other and, like Django’s URL handling and include, will strip off the matched part of the URL in the outer router and leave only the unmatched portion for the inner router, allowing reusable routing files.

Note that you cannot use the Django include function inside of the URLRouter as it assumes a bit too much about what it is given as its left-hand side and will terminate your regular expression/URL pattern wrongly.

Login and Logout

As well as overhauling the internals of the AuthMiddleware, there are now also login and logout async functions you can call in consumers to log users in and out of the current session.

Due to the way cookies are sent back to clients, these come with some caveats; read more about them and how to use them properly in Authentication.

In-Memory Channel Layer

The in-memory channel layer has been extended to have full expiry and group support so it should now be suitable for drop-in replacement for most test scenarios.

Testing

The ChannelsLiveServerTestCase has been rewritten to use a new method for launching Daphne that should be more resilient (and faster), and now shares code with the Daphne test suite itself.

Ports are now left up to the operating system to decide rather than being picked from within a set range. It also now supports static files when the Django staticfiles app is enabled.

In addition, the Communicator classes have gained a receive_nothing method that allows you to assert that the application didn’t send anything, rather than writing this yourself using exception handling. See more in the Testing documentation.

Origin header validation

As well as removing the print statements that accidentally got into the last release, this has been overhauled to more correctly match against headers according to the Origin header spec and align with Django’s ALLOWED_HOSTS setting.

It can now also enforce protocol (http versus https) and port, both optionally.

Bugfixes & Small Changes

  • print statements that accidentally got left in the Origin validation code were removed.
  • The runserver command now shows the version of Channels you are running.
  • Orphaned tasks that may have caused warnings during test runs or occasionally live site traffic are now correctly killed off rather than letting them die later on and print warning messages.
  • WebsocketCommunicator now accepts a query string passed into the constructor and adds it to the scope rather than just ignoring it.
  • Test handlers will correctly handle changing the CHANNEL_LAYERS setting via decorators and wipe the internal channel layer cache.
  • SessionMiddleware can be safely nested inside itself rather than causing a runtime error.

Backwards Incompatible Changes

  • The format taken by the OriginValidator for its domains has changed and *.example.com is no longer allowed; instead, use .example.com to match a domain and all its subdomains.
  • If you previously nested URLRouter instances inside each other both would have been matching on the full URL before, whereas now they will match on the unmatched portion of the URL, meaning your URL routes would break if you had intended this usage.