-
Notifications
You must be signed in to change notification settings - Fork 295
Add experimental support for streaming SSE in live mode. #2544
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
Conversation
✅ Deploy Preview for electric-next ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
b11fc3c to
a52a353
Compare
|
As per my previous discord note about diffing, the payload format of: To send the smallest insert is not exactly optimal. Perhaps it gzips down ok over the wire to remove the duplication but it's possible to consider many approaches that could optimise down to an enum code and value, perhaps with a new offset at the end of the stream. |
icehaunter
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
|
If |
Perhaps even drop it from the headers? |
|
yeah, but should also be clear that this is an SSE response from the headers (in case it isn't already) because this is a protocol change |
Agree. Could add a flag in the headers that indicates this is an SSE response. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On a 409 the returned location header is wrong:
curl -i 'http://localhost:3000/v1/shape?table=foo&offset=26783992_0&handle=103702391-174791678028&live=true&experimental_live_sse=true'
HTTP/1.1 409 Conflict
date: Thu, 22 May 2025 12:32:23 GMT
content-length: 48
vary: accept-encoding
cache-control: public, max-age=60, must-revalidate
x-request-id: GEHZYbPCsu850hcAAAHB
electric-server: ElectricSQL/1.0.5
access-control-allow-origin: *
access-control-expose-headers: *
access-control-allow-methods: GET, HEAD, DELETE, OPTIONS
content-type: application/json; charset=utf-8
etag: "103702391-1747916780281::"
location: /v1/shape?experimental_live_sse=true&handle=103702391-1747916780281&offset=-1&table=foo
electric-handle: 103702391-1747916780281
electric-schema: {"a":{"type":"int4","not_null":true,"pk_index":0},"b":{"type":"int4"}}
data: [{"headers":{"control":"must-refetch"}}]
The location header contains the experimental_live_sse=true param but it does not include the live param, which is an invalid combination. So if i curl the returned location i get a 400:
curl -i 'http://localhost:3000/v1/shape?experimental_live_sse=true&handle=103702391-1747916780281&offset=-1&table=foo'
HTTP/1.1 400 Bad Request
date: Thu, 22 May 2025 12:33:29 GMT
content-length: 107
vary: accept-encoding
cache-control: no-cache
x-request-id: GEHZcSpbuSks7l4AAAIh
electric-server: ElectricSQL/1.0.5
access-control-allow-origin: *
access-control-expose-headers: *
access-control-allow-methods: GET, HEAD, DELETE, OPTIONS
content-type: application/json; charset=utf-8
electric-schema: null
{"message":"Invalid request","errors":{"experimental_live_sse":["can't be true unless live is also true"]}}
|
Also, the Then i delete the shape, and curl again and i get a JSON array: |
This is a follow up PR on #2546 and #2544. It solves a bug related with 409s (must refetch) in SSE mode and it replaces the EventSource browser API by the [fetch-event-source](https://github.com/Azure/fetch-event-source) library. I refactored the `ShapeStream.#start` method which was becoming very big and complex. To this end, i split the logic into helper methods that handle the different parts that need to happen (building the shape URL, making the request, parsing the response headers, handling the response body, etc.). I had to patch the [fetch-event-source](https://github.com/Azure/fetch-event-source) library because it relies on browser-specific features such as `document` and `window` (cf. Azure/fetch-event-source#41). But we want our client to also work in server-side JS environments. I also had to patch the `fetch-event-source` library because it does not abort the fetch when you pass an already aborted signal. A complete description of the bug and the fix can be found here: Azure/fetch-event-source#98.
|
Shipped in #2776 |
…#2546) Co-authored-by: Kevin <kevin@electric-sql.com>
|
I rebased this in #2856 and merged into main. |
If you add
experimental_live_sse=trueto your live requests, then the server streams SSEs rather than returning immediately when there's new data.Requests are closed after 60 seconds, in order to support request collapsing. We also diverge slightly from default SSE behaviour by requiring the client to re-connect on a new URL once the request is closed. Because we require the client to honour our API mechanism of advancing the offset.
This can be worked around using a standard JS EventStream client by closing in the event of error and reconnecting manually. Just a rough sketch for reference:
Note that the HTTP headers are returned at the start of the response. This means that the current header mechanism to return the next offset isn't valid. At the moment, you get a response like this:
The
global_last_seen_lsnis the correct lsn to resume from, so you can reconnect with e.g.:offset= 5501319691220014840_0and it will continue streaming from the correct point.I've tried to make sure that I keep everything a stream and don't either materialise or encode anything potentially expensive.