Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I close a Server-Send Events connection in Flask?

The below has given an answer using node.js.

How to close a "Server-Sent Events"-connection on the server?

However, how to do the same thing in python Flask?

like image 997
hllau Avatar asked Jul 22 '12 02:07

hllau


People also ask

How do you stop a server from sending events?

The browser can stop processing events by calling . close() on the EventSource object. This closes the HTTP connection — the server should detect this and stop sending further events as the client is no longer listening for them.

How do I close SSE?

Once you have all your details just call our Customer Service team on 0818 81 22 20 to close your account.

How does server-sent events work?

SSE is designed to use the JavaScript EventSource API in order to subscribe to a stream of data in any popular browser. Through this interface a client requests a particular URL in order to receive an event stream. SSE is commonly used to send message updates or continuous data streams to a browser client.

How do I send events from server to client?

The server-sent events streaming can be started by the client's GET request to Server. Accept: text/event-stream indicates the client waiting for event stream from the server, Cache-Control: no-cache indicates that disabling the caching and Connection: keep-alive indicates the persistent connection.


1 Answers

It is important to note you need to close the connection on the client as well, otherwise it will try and reopen the connection after a retry timeout.

This was confusing me until I saw this post here: https://stackoverflow.com/a/38235218/5180047

From the link:

The problem here is that the server unexpectedly closes the connection, instead of doing its work while leaving it open. When this happnes, the client re-sends a request to open a connection and to start streaming Server Sent Events. The server then closes the connection again and again, leading to an infinite loop.

After I saw this.. my preferred solution was to close the connection from the server by yielding an expected data message.

On the client (browser)

var sse = new EventSource('/sse');
sse.addEventListener('message', function(e) {
  console.log(e);
  var data = e.data;
  if (!data) {
      console.log('no data in event');
      return;
  }
  if (data === 'finished') {
      console.log('closing connection')
      sse.close()
  }
  // my work here based on message
});

My Flask Server

from flask import Response

@app_api.route("/sse")
def stream():
    def trackerStream():
        finished = check_if_finished()
        while not finished:
            sleep(1) # poll timeout
            if should_send_event():
                yield f"data: {mydata()}\n\n"
            else:
                yield "data: nodata\n\n"

            finished = check_if_finished()

        yield "data: finished\n\n"

    return Response(trackerStream(), mimetype="text/event-stream")

Note: Make sure you're always sending events at some interval from the server to the client. If the user closes the browser, flask will get an error while trying to write to the socket and will close the stream for you. If you aren't writing to the client at some interval, even if you're just writing data: nodata\n\n, then the server could get stuck in a loop.

like image 84
Nick Brady Avatar answered Oct 07 '22 18:10

Nick Brady