Open matpen opened 2 years ago
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
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'.
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++
}
}
I set up a simple test where the following happens:
EventSource
;id
field;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.