Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SSE (EventSource) times out after 1 hour 22 minutes. Is there any way to keep it persistent?

I have an area in my page where messages go when a database has changed. Now, some days the database will change so much that a new message is displayed every 10 minutes; other days it will change only a few times. The issue I am having is that the EventSource seems to time out after 1hr 22 minutes, and no longer will the browser receive notifications.

I am wondering if there is a way to keep EventSources persistent (i.e., for as long as the browser is displaying the page, the EventSource is alive). According to what I have found in my Google searches, EventSources should remain alive until the tab/window is closed. Unfortunately, there seems to be so very little that I find in my Google searches, and for me this doesn't seem to be the case.

like image 557
Franz Kafka Avatar asked Nov 04 '13 22:11

Franz Kafka


People also ask

Is SSE long polling?

Long-Polling, Websockets, Server-Sent Events (SSE), and Comet are some of the ways for the client-side to connect with the server-side in real-time.

How do you stop responding to events in a stream?

Cancel an event stream # To cancel a stream from the server, respond with a non text/event-stream Content-Type or return an HTTP status other than 200 OK (e.g. 404 Not Found ). Both methods will prevent the browser from re-establishing the connection.

How do SSE 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 does event Source work?

An EventSource instance opens a persistent connection to an HTTP server, which sends events in text/event-stream format. The connection remains open until closed by calling EventSource. close() . Once the connection is opened, incoming messages from the server are delivered to your code in the form of events.


2 Answers

You don't say where the socket closure is happening (on the browser, socket on client machine, socket on server-side, etc.) but it doesn't really matter as the fix is the same for all of them: send keep-alive messages.

The server should send a keep-alive message. Either every, say, 15 seconds; or only after 15 seconds of inactivity. (Whichever is easier to code, server-side, for you.) It can be as simple as an SSE comment: ":\n\n" (lines starting with colons are ignored). I prefer to send actual data, because:

  • You get to see a message, allowing client-side keep-alive checking (see below)
  • There is bound to be something useful you want to send, like a timestamp (for a check that client/server clocks are in sync), or metrics, etc.

On the client-side, run a timer with setTimeout() set to 20 seconds. Each time you receive any data from the server (whether genuine data, or your keep-alive), kill the timer, and start it again. Therefore the only time the time-out function will get called is if your server went more than 20 seconds without sending you anything. When that happens, kill the connection and reconnect.

The above is assuming the problem is at the socket-level. The problem might instead be the browser is crashing: perhaps it has run out of memory. The fix I'd do in that case is a once/hour timer (setTimeout() in JavaScript), to manually close and re-open the EventSource connection. Or clear out some memory buffers you might be using. A bit of profiling with FireBug or Chrome tools will tell you if you have a memory problem.

Plug: Over half of the "Making our App production quality" chapter in my coming-soon SSE book is about keep-alive and using LastId on the reconnect. Please buy when it comes out :-)

like image 58
Darren Cook Avatar answered Sep 20 '22 07:09

Darren Cook


I had the same problem with Chrome reporting "net::ERR_SPDY_PROTOCOL_ERROR 200" every two minutes.

Sending SSE comments every minutes solved the problem for me. See example Nodejs / Express code below.

exports.addWebServices = function(app) {
  app.get('/ws/clientEvent', function(req, res) {
    res.writeHead(200, {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache',
      'Connection': 'keep-alive'
    })

    /* Event handlers for SSE here */

    let keepAliveMS = 60 * 1000;

    function keepAlive() {
      // SSE comment for keep alive. Chrome times out after two minutes.
      res.write(':\n\n');
      setTimeout(keepAlive, keepAliveMS);
    } 

    setTimeout(keepAlive, keepAliveMS);
  }

}
like image 32
Wade Avatar answered Sep 20 '22 07:09

Wade