Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java spring SseEmitter/ResponseBodyEmitter: detect browser reloads

Tags:

java

spring

I'm using server-side events (SSE) in Java Spring. Whenever a new client subscribes to the events service I execute the following code at the REST controller:

SseEmitter emitter = new SseEmitter(-1L);
emitter.onCompletion(() -> {
        logger.debug(TAG + "Emitter completed.");
        emitters.remove(emitter);
    });
return emitter;

Then, whenever an event needs to be notified to the clients I execute:

 for (ResponseBodyEmitter emitter: emitters) {
        emitter.send("Message #1");
 }

The problem is that when one of the clients reloads the browser, the emitter does not get completed (as I expected), and I get a broken pipe exception when calling the code above. Only after this exception is triggered I see the emitter being completed.

Is there a way to solve this problem?

like image 700
Damian Nadales Avatar asked Dec 30 '15 13:12

Damian Nadales


1 Answers

When the browser reloads, it will establish a new EventSource to your server, right? Your problem is with the old one, which has no client endpoint anymore.

I suggest you try to detect that it is the same client connecting, and then explicitly call complete on the old emitter.

In my case I can detect this based on a token which the EventSource passes in as a URL parameter. When I hook the newly created emitter to a "user object", I make sure to complete the previous emitter before assigning the new to the user field variable.

From your code, it seems you have a list or set of emitters. Can you maybe make it a map instead, where you have some client identity as the key, and the emitter as the value?

I can't tell you exactly what piece of information to use as a client identity, since it all depends on your application. In my case it is a JWT token, but you could perhaps simply create a client numbering scheme...

like image 150
Leif John Avatar answered Nov 10 '22 11:11

Leif John