Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Header Last-Event-ID is not automatically sent on reconnect #291

Open
matpen opened this issue Sep 8, 2022 · 3 comments
Open

Header Last-Event-ID is not automatically sent on reconnect #291

matpen opened this issue Sep 8, 2022 · 3 comments

Comments

@matpen
Copy link

matpen commented Sep 8, 2022

I set up a simple test where the following happens:

  1. on client-side, we connect to the server with EventSource;
  2. the server will start sending events, once every two seconds: the events contain the id field;
  3. on client-side, we log the received events, to verify that everything is working correctly;
  4. then the server is intentionally restarted, in order to simulate a loss of connection;
  5. the client will wait a few seconds, then correctly re-attempt connection: however, in this case the header Last-Event-ID is not sent to the server.

IIUC this does not conform to the specs. This is also confirmed by running the test described above with the native implementation of EventSource in Chrome (i.e. not this repo), which correctly sends the header.

@SimonX200
Copy link

I am currently implementing and testing SSE too.

Here that last-event-id works.

On reconnect the last received id is sent back as last-event-id.

We use eventsource 2.0.2 for the test-client and nestjs 9.1.2 as backend

@sse('sse')
public async sseEndpoint(
@headers('last-event-id') lastEventId: string,
@query('request') requestStr: string
): Promise<Observable> {
return await data(requestStr, lastEventId);
}

@SimonX200
Copy link

SimonX200 commented Jan 5, 2023

A more detail testing shows that there is a problem with multiple reconnects in a row.

If one reconnect fails with some http-error-code then the next successful reconnect sends the first ever received id as last-event-id.

A single successful reconnect attempt always sends the correct last-event-id.

BTW: Actually the last-event-id that is sent after multiple failed reconnects is always '1'.

@joebailey26
Copy link

joebailey26 commented Mar 18, 2023

I was hitting rate limits with this bug as there would be continuous reconnects to my server, rather than waiting the 10 seconds like I wanted.

To get around this, I've written some code on the client side of my application that others might find helpful.

// Add some variables
let hasSseTimerExpired = false
let sseTimer = null
let isFirstSseRequest = true
let sseRetries = 0
function start_sse_timer () {
      hasSseTimerExpired = false
      sseTimer = setTimeout(() => {
        hasSseTimerExpired = true
      }, 9000)
}
function start_sse () {
        // If we already have a timer running, stop it
        if (sseTimer) {
          clearTimeout(this.sseTimer)
        }
        // Start the timer as we are starting the connection
        set_sse_timer()
        // Set isFirstSseRequest to true, as this time, we receive a response immediately
        isFirstSseRequest = true
        // Code to start the SSE connection
        ...
}
function stop_sse () {
      // Code to stop your SSE connection
      ...
}
function on_sse_message_received() {
      // If the timer has expired, it means it's been longer than 9 seconds so we can continue to process the request
      // We also check if this is the first request, if it is, we can ignore the timer as a response is returned immediately
      if (hasSseTimerExpired || isFirstSseRequest) {
          // We set the timer as we are now waiting on the next SSE request
          set_sse_timer()
          // We set isFirstSseRequest to false as we have now processed the first request
          if (isfirstSseRequest) {
                isFirstSseRequest = false
          }
          // Code to process the response from the SSE connection
          ...
          // We only want to retry this 3 times to avoid hammering the server
      } else if (sseRetries < 3) {
          // Restart SSE as something has gone wrong and a response has been returned sooner than 9 seconds
          sse_end()
          sse_start()
          sseRetries++
      }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants