0

I have an existing Django Channels setup that is working with websockets and I have to add another endpoint to support SSE. I'm following an example from here https://channels.readthedocs.io/en/stable/topics/consumers.html to set up a consumer using AsyncHttpConsumer and I've been getting an error:

TypeError: ServerSentEventsConsumer() missing 2 required positional arguments: 'receive' and 'send'

My setup is as follows:

playground/consumers.py

from datetime import datetime
from channels.generic.http import AsyncHttpConsumer

class ServerSentEventsConsumer(AsyncHttpConsumer):
    async def handle(self, body):
        await self.send_headers(headers=[
            (b"Cache-Control", b"no-cache"),
            (b"Content-Type", b"text/event-stream"),
            (b"Transfer-Encoding", b"chunked"),
        ])
        while True:
            payload = "data: %s\n\n" % datetime.now().isoformat()
            await self.send_body(payload.encode("utf-8"), more_body=True)
            await asyncio.sleep(1)

playground/asgi.py

import os
import django
from django.core.asgi import get_asgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'playground.settings.production')
django.setup()
application = get_asgi_application()

playground/routing.py

from playground.asgi import application
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.security.websocket import AllowedHostsOriginValidator

from .consumers import (
    BaseConsumer,
    ServerSentEventsConsumer,
)
from django.urls import path, re_path

application = ProtocolTypeRouter(
    {
        "http": application,
        "websocket": AllowedHostsOriginValidator(
            JwtAuthMiddlewareStack(
                URLRouter(
                    [
                        re_path(r"^wss$", BaseConsumer),
                        re_path("sse", ServerSentEventsConsumer.as_asgi()) # <- Desperate attempt. I don't wanna use websockets.
                    ]
                )
            )
        ),
    }
)

playground/urls.py

urlpatterns = [
    path("sse/", ServerSentEventsConsumer.as_asgi(), name="sse")
]

I am using the following software versions:

asgiref = "3.7.2"
Django = "4.0.10"
channels-redis = "4.1.0"
channels = "4.0.0"

I've seen some related issues where people resolved them by downgrading Channels to version 3. This is not an option for me since it was a major team effort to upgrade to Django 4 to begin with.

Any input will be highly appreciated.


UPDATE #1

I've tried downgrading Channels to a lower version and I'm still getting the same error:

asgiref = "3.7.2"
channels = "3.0.5"
channels-redis = "3.4.1"
daphne = "3.0.2"
Sthe
  • 2,575
  • 2
  • 31
  • 48

1 Answers1

0

I finally managed to make this work by just making the following changes:

playground/routing.py

from playground.asgi import application
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.security.websocket import AllowedHostsOriginValidator

from .consumers import (
    BaseConsumer,
    ServerSentEventsConsumer,
)
from django.urls import path, re_path

application = ProtocolTypeRouter(
    {
-       "http": application, # <-- removed this
+       "http": URLRouter([
+           path("sse/<str:username>": ServerSentEventsConsumer.as_asgi()),
+           path(r"", application),
+       ]),
        "websocket": AllowedHostsOriginValidator(
            JwtAuthMiddlewareStack(
                URLRouter(
                    [
                        re_path(r"^wss$", BaseConsumer)
                    ]
                )
            )
        ),
    }
)
Sthe
  • 2,575
  • 2
  • 31
  • 48