Hello Django fans!
I’m writing a Django app that involves sending notifications to users via long-polling and Server-Sent Events (SSE). My actual app does some moderately complicated stuff involving redis pub/sub channels, but this simplified code illustrates the basic technique that I’m using:
async def date_view(request: HttpRequest) -> StreamingHttpResponse:
"""Send the current date to the client every 1s."""
return StreamingHttpResponse(
date_stream(),
content_type="text/event-stream",
headers={
"X-Accel-Buffering": "no",
"Cache-Control": "no-cache",
},
)
async def date_stream() -> AsyncIterator[bytes]:
"""Generates SSE messages containing the date."""
while True:
await asyncio.sleep(1)
yield utils.sse_message(
data=timezone.now().isoformat().encode("utf8"),
event="date"
)
When I run this with Daphne, I get lots of error messages like this (I inserted some line breaks for readability):
WARNING 2023-07-16 00:33:58,168 server 815074 140525947258432
Application instance
<Task pending name='Task-1'
coro=<ASGIStaticFilesHandler.__call__() running at
/path/to/python3.10/site-packages/django/contrib/staticfiles/handlers.py:101>
wait_for=<Future pending cb=[Task.task_wakeup()]>>
for connection
<WebRequest at 0x7fcec0f96ad0 method=GET
uri=/notifications clientproto=HTTP/1.1>
took too long to shut down and was killed.
I assume this is because the while True
loop runs forever, with nothing to stop it once the client disconnects.
My question: is there a way to gracefully detect disconnects? Something like Starlette’s request.is_disconnected
. It seems like various parts of the stack do have this info, but I haven’t been able to find an elegant way of accessing it from my view.