Forums

Server Sent Events (SSE) and PythonAnywhere

I'm trying to get SSE working on my PythonAnywhere server for the first time. My code all works locally, but of course it is the Werkzeug dev enviro and so doesn't have the multiprocessing issues of a real server. What I'm looking for is some direction on a recommended way to do this on PythonAnywhere in case the way it is hosted or configured requires specific solutions.

Here is my code that initiates an SSE connection from a browser request:

@webapp_blueprint.route('/webapp/sse_subscribe',  methods=['GET'])
def sse_subscribe():
    listen_key = some_user_specific_value()

    def stream():
        messages = app.announcer.listen(listen_key)
        while True:
            msg = messages.get()  # blocks until a new message arrives
            yield msg

    response = flask.Response(stream(), mimetype='text/event-stream')

    return response

Notes about this:

  • app.announcer is a global variable, a single "MessageAnnouncer" class that keeps a list of Python Queues for every user.
  • app.announcer.listen creates a Queue; the "messages" variable contains a Queue.

How it looks from the client: the browser connects to sse_subscribe and the connection remains open for exactly the five minutes that PythonAnywhere has defined as the lifetime of a connection with no activity. So I need to implement a ping to keep it open, that's understood - assuming that keeping connections open like this is an acceptable way to handle SSE on a PythonAnywhere server.

How it fails: the app.announcer persists fine between connections but the Queues that it creates are always gone when an event happens and the announcer attempts to put_nowait to the Queue. This makes sense in a multiprocessing environment; I haven't done anything to manage sharing those Queues.

So how do you make that work? The Queue objects need to remain alive and be accessed by any future HTTP request. Do I build a multiprocessing manager or is there a better way?

That does not look like something that would work on PythonAnywhere. Worker processes are ephemeral. See https://help.pythonanywhere.com/pages/AsyncInWebApps/