spring-bootspring-mvcserver-sent-events

SSE events not being received until SseEmitter is complete


I am new to Server Sent Events (SSE) and am trying to get them working in my Spring Boot app. The problem I am having is that it doesn't seem like the events are getting sent until complete is called on the SseEmitter. In the following example I will get all (10) events plus the complete message after 10 seconds instead of one every second.

<button id="startevents" type="button" class="btn btn-primary">
   Start Events
</button>

<script>
   document.getElementById('startevents').addEventListener('click', function() {
      const eventSource = new EventSource('/events');
      eventSource.addEventListener('myevent', function(event) {
         console.log('myevent: ', event.data);
      });
      eventSource.addEventListener('complete', function(event) {
         console.log('complete: ', event.data);
         eventSource.close();
      });
      eventSource.addEventListener('error', function(event) {
         console.log('error: ', event);
      });
   });
</script>
  @GetMapping( "/events" )
  public SseEmitter republishEvents() {
    SseEmitter sseEmitter = new SseEmitter(Long.MAX_VALUE);
    
    sseEmitter.onCompletion(() -> {
      log.info("SSE complete");
    });
    sseEmitter.onTimeout(() -> {
      log.warn("SSE timeout");
      sseEmitter.complete();
    });
    sseEmitter.onError((e) -> {
      log.error("SSE error", e);
      sseEmitter.complete();
    });

    ExecutorService executor = Executors.newSingleThreadExecutor();
    executor.execute(() -> {
      try {
        for ( int i = 0; i < 10; i++ ) {
          log.debug( "Sending event " + i );
          SseEmitter.SseEventBuilder event = SseEmitter.event()
              .name("myevent")
              .data( "Event " + i );
          sseEmitter.send(event);
          Thread.sleep( 1000 );
        }
        log.debug( "Sending complete event" );
        SseEmitter.SseEventBuilder event = SseEmitter.event()
            .name("complete")
            .data( "complete" );
        sseEmitter.send(event);
        sseEmitter.complete();
      } catch ( Exception e ) {
        log.error( "Error sending event", e );
        sseEmitter.complete();
      } finally {
        executor.shutdown();
      }
    });

    return sseEmitter;
  }

Solution

  • After recreating projects from scratch, that worked just fine, I eventually decided to fire up Wireshark just to see if the events were really getting sent out or not. That's when I remembered I had an nginx running locally to handle the certs and ports. Sure enough, it was buffering the events.

    I added the following and everything now works fine:

    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_buffering off;