I’m trying to implement simple SSE with Django Channel’s AsyncHttpConsumer.
My minimal example:
class BaseSSEConsumer(AsyncHttpConsumer, ABC):
cors_headers = [
(b"Access-Control-Allow-Origin", b"*"),
(b"Access-Control-Allow-Methods", b"GET, OPTIONS"),
(
b"Access-Control-Allow-Headers",
b"Content-Type, Cache-Control, Authorization",
),
]
default_headers = [
(b"Cache-Control", b"no-cache"),
(b"Content-Type", b"text/event-stream"),
(b"Transfer-Encoding", b"chunked"),
*cors_headers,
]
async def handle(self, body):
await self.send_headers(status=200, headers=self.default_headers)
params = self._parse_query_params()
message = {
"type": "sse",
"data": {
"timestamp": datetime.now().isoformat(),
"params": params,
},
}
event = f"data: {json.dumps(message)}\n\n"
while True:
print(f"Sending SSE message")
await self.send_body(body=event.encode(), more_body=True)
await asyncio.sleep(1)
async def disconnect(self, close_code=None):
print("Disconnecting BaseSSEConsumer")
def _parse_query_params(self) -> dict[str, list]:
query_string = self.scope["query_string"].decode()
return parse_qs(query_string)
I’m successfully sending events. When i close a browser’s tab the disconnect method doesn’t get called, instead after waiting for a few seconds i get following exception:
Application instance <Task pending name='Task-1' coro=<ASGIStaticFilesHandler.__call__() running at /usr/local/lib/python3.13/site-packages/django/contrib/staticfiles/handlers.py:101> wait_for=<Future pending cb=[Task.task_wakeup()]>> for connection <WebRequest at 0x7f5495d35d30 method=GET uri=/api/sse/?symbols=AAPL%2CGOOG%2CMSFT clientproto=HTTP/1.1> took too long to shut down and was killed.
I’m running the runserver with daphne.
Things i tried without success:
- changing the server to uvicorn
- offloading request processing to another thread
Is disconnecting from client supported by Channels? Should disconnect method be called after closing browser’s tab? Thanks!