After a lot of banging on things and reading framework code, I've found
think is the right answer to this question.
1. According to the WSGI PEP, if your application returns an iterator with a
close() method, it should be called by the WSGI server once the response has
finished. Django supports this too. That's a natural place to do the Redis
connection cleanup that I need.
2. There's a bug in Python's wsgiref implementation, and by extension in
Django's 'runserver', that causes close() to be skipped if the client
disconnects from the server mid-stream. See
I've submitted a patch.
3. Even if the server honors close(), it won't be called until a write to
client actually fails. If your iterator is blocked waiting on the pubsub and
not sending anything, close() won't be called. I've worked around this by
sending a no-op message into the pubsub each time a client connects. That
when a browser does a normal reconnect, the now-defunct threads will try to
write to their closed connections, throw an exception, then get cleaned up
the server calls close(). The SSE spec says that any line beginning with a
colon is a comment that should be ignored, so I'm just sending ":\n" as my
no-op message to flush out stale clients.
Sample code for doing this is posted on the Stack Overflow page where I also
posted this question. See