aseolin
aseolin

Reputation: 1200

Server-sent event lost connection

I'm following this tutorial and I'm putting the returned data on console log in Chrome. Here is my code on client side:

$(document).ready(function() {  

  //check for browser support
  if(typeof(EventSource)!=="undefined") {

    var source = new EventSource("URL/sse");
    //detect message receipt       
    source.addEventListener("message", function(e) {
        console.log(e.data);            
    }, false);

    source.addEventListener("open", function(e) {
        console.log("Connection was opened.");
    }, false);


    source.addEventListener("error", function(e) {
        if (e.readyState == EventSource.CLOSED) {
            console.log("Connection lost.");
        }            
    }, false);
  }
  else {
    // No support
  }
});

The data is ok. When I access the webpage, my console log is opening and closing the connection every 3 seconds:

mypage.js:39 Connection was opened.
mypage.js:15 [{"John":"1","Doe":"2"}]
mypage.js:44 Error - Connection lost.
// 3 seconds
mypage.js:39 Connection was opened.
mypage.js:15 [{"John":"1","Doe":"2"}]
mypage.js:44 Error - Connection lost.
// 3 seconds
mypage.js:39 Connection was opened.
mypage.js:15 [{"John":"1","Doe":"2"}]
mypage.js:44 Error - Connection lost.
...

Here is my server-side code:

@Singleton
@Path("/sse")
public class SSEResource {

  @GET
  @Produces(SseFeature.SERVER_SENT_EVENTS)
  public EventOutput getServerSentEvents() {
    final EventOutput eventOutput = new EventOutput();

    new Thread(new Runnable() {

        @Override
        public void run() {
            try {
                final OutboundEvent.Builder eventBuilder = new OutboundEvent.Builder();
                eventBuilder.name("message");

                final String myString = getData.toString(); // Some data from db

                eventBuilder.data(String.class, myString);

                final OutboundEvent event = eventBuilder.build();
                eventOutput.write(event);

            } catch (Exception e) {
                throw new RuntimeException("Error when writing the event.",
                        e);
            } finally {

                try {
                    eventOutput.close();
                } catch (IOException ioClose) {
                    throw new RuntimeException(
                            "Error when closing the event output.", ioClose);
                }
            }
        }
    }).start();
    return eventOutput;
  }
}

From what I understand, the connection should remain open until the client decided to close it. What am I doing wrong? Is that correct?

Upvotes: 1

Views: 1928

Answers (1)

user3617762
user3617762

Reputation: 31

Your server code is closing the EventOutput.

           try {
                eventOutput.close();
            } catch (IOException ioClose) {
                throw new RuntimeException(
                        "Error when closing the event output.", ioClose);
            }

This causes the client to reconnect and the process starts again.

I'm not 100% sure what you are doing. If you want to send more data in the thread, you need to not close the EventOutput.

According to the specification you can send a HTTP 204 No Content response code to prevent the client from reconnecting, I'm not sure how to do this using Jersey SSE though. I was searching for the answer when I came across this question.

In your case you could send a message that causes the client to close the connection, or prevents it from reconnecting.

Upvotes: 1

Related Questions