I just wanted to plug my blog post about using the async capabilities of StreamingHttpResponse in Django 4.2 to stream Server-Sent Events and use PostgreSQLs LISTEN/NOTIFY as a way to broadcast events to be streamed.
EDIT:// Actually this was backported to 4.2.1, the issue is that Django here simply doesn’t work with an AsyncCursor and probably will not in the forseeable future. Sorry for the noise.
Thank you for sharing this guide. I love the clever combination of HTMX, SSE, async and Postgres NOTIFY mechanism.
This solution & design can work great for a small number of people in the chat. But it may not work with say 10,000 online users.
Each online user requires an open connection to the database. Number of maximum connections depends on how beefy your postgres server is. For a basic instance it can be a 100 connections, for a beefy one maybe 5000.
Hi @valberg ,
thank you, this post came exactly when i was looking for implementing such!
a question for you: when running in dev mode (runserver) and changing the code inline, the server restarts (by design) and then this mechanism crashes with:
Traceback (most recent call last):
File "/usr/lib/python3.10/site-packages/django/core/handlers/exception.py", line 55, in inner
response = get_response(request)
File "/usr/lib/python3.10/site-packages/django/core/handlers/base.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/usr/lib/python3.10/site-packages/asgiref/sync.py", line 250, in __call__
loop_future = loop_executor.submit(
File "/usr/lib/python3.10/concurrent/futures/thread.py", line 169, in submit
raise RuntimeError('cannot schedule new futures after '
RuntimeError: cannot schedule new futures after interpreter shutdown
Yes it definitely would benefit with some way of pooling - when I get the time I’m going to investigate how to make it more performant (if that is even possible).
Pooling is always a good idea. It’s enabled by default in most of driver implementations IIRC. But won’t help since NOTIFY subscriptions are blocking. Perhaps some pubsub able platform like Redis could do the trick, but it’s a whole different story Although that can be an overkill if one is good with <5k concurrent users.
I’m very shallow-knowledge in Django, but it’s always happen after I save code, in dev. So it’s probably the dev server restarting after the save would kill something that does not come back up automatically. I’m not sure if that wouls manifest in production because the is no save in production, I have not gotten there yet.