Search code examples
djangowebsocketdjango-channels

How to use multiple websocket connections using Django Channels?


I have been happily using Django-Channels for several months now. However, I went to add a second websocket dependent application to my Django project and I am running into trouble.

The error I am getting is websocket connection failed websocket is closed before the connection is established. What is odd is that the first application was working before the second application was deployed. Further, the first application continues to work so long as the second application is not running.

The Django Channels documentation says:

Channels routers only work on the scope level, not on the level of individual events, which means you can only have one consumer for any given connection. Routing is to work out what single consumer to give a connection, not how to spread events from one connection across multiple consumers.

I think this means that Django-Channels does not support routing for multiple websocket connections. That is, I think I am trying to use the same websocket connection/port for two different applications. My routing.py file looks as follows:

application = ProtocolTypeRouter({
    "websocket": AuthMiddlewareStack(
        URLRouter([
            path("first_application/stream/", app_1_consumers.AsyncApp1),
            path("second_application/stream/", app_2_consumers.AsyncApp2),
        ])
    )
})

When I attempted to use the setup below, it could not find the path to the first application:

application = ProtocolTypeRouter({
    "websocket": AuthMiddlewareStack(
        URLRouter([
            path("second_application/stream/", app_2_consumers.AsyncApp2),
        ])
    ),
    "websocket02": AuthMiddlewareStack(
        URLRouter([
            path("first_application/stream/", app_1_consumers.AsyncApp1),
        ])
    ),

})

How can I setup my Django application to serve up two different websocket connections using Django-Channels? Is it possible? Or am I just configuring things improperly?


Solution

  • According to their implementation and documention (here), the value to the ProtocolTypeRouter is a map/dict and all they listen or view for is two types of keys:

    ProtocolTypeRouter({
       "http": some_app,
       "websocket": some_other_app,
    })
    

    Which brings to the fact that if you pass different key like websocket02 it will not work. Which would obviously mean there has to be a way to combine both the APP url's via same websocket and create separate endpoint.

    Infact, what you can do is, something like they have mentioned:

    from django.conf.urls import url
    
    from channels.routing import ProtocolTypeRouter, URLRouter
    from channels.auth import AuthMiddlewareStack
    
    application = ProtocolTypeRouter({
    
        # WebSocket chat handler
        "websocket": AuthMiddlewareStack(
            URLRouter([
                url(r"^first_application/stream/$", app_2_consumers.AsyncApp1Consumer),
                url(r"^second_application/stream/$", app_2_consumers.AsyncApp2Consumer),
            ])
        ),
    
    })
    

    The above example is based on their implementation for two endpoints (here):

    application = ProtocolTypeRouter({
    
        # WebSocket chat handler
        "websocket": AuthMiddlewareStack(
            URLRouter([
                url(r"^chat/admin/$", AdminChatConsumer),
                url(r"^chat/$", PublicChatConsumer),
            ])
        ),
    })
    

    OR

    route based on different channels under same websocket: https://github.com/django/channels/blob/master/docs/topics/routing.rst#channelnamerouter