0xK.co/s
tasos@kadena.io
September 29, 2023
whois
“Tasos Bitsios”Streaming protocol
Essentially a streaming GET
Best suited for UTF-8 updates
Especially for multiple update channels
Tradeoff: more connections vs querying your data store
Not really
Unidirectional & UTF-8
curl
it ✅// TODO
🥳 SSE is 19 years old
🧙 By Ian Hickson, while at Opera
🔧 13 years of mainstream support
Contemporary to Web sockets, HTML5, <video>
, Web workers, Web storage
Narrow use case
<>
The simplest server-sent event stream specifies just data
events.
> GET /stream/hello HTTP/1.1
< HTTP/1.1 200 OK
< Content-Type: text/event-stream
< data: Hello\n\n
< data: ReactLive are you there?\n\n
Events separated by two newline characters \n\n
Data is encoded in UTF-8 (mandatory)
Playground: “simple” scenario
Client-side: SSE consumer API is EventSource
let i=0;
const source = new EventSource("http://localhost:3001/stream/simple");
// "message" event emitted for each "data" event received
source.addEventListener("message", event => console.log(++i, event.data), false);
// or .onmessage = (...) if that is your jam
< HTTP/1.1 200 OK
< Content-Type: text/event-stream
< data: Hello\n\n
< data: ReactLive are you there?\n\n
1 Hello
2 ReactLive are you there?
You can “namespace” your events using the event
field with any custom name:
< event: goal
< data: "ARS-LIV 1-1 45"\n\n
< event: spectator-chat
< data: "Did you see that ludicrous display just now"\n\n
The goal
and spectator-chat
events are handled separately on the frontend
Scan the QR to interact with this presentation directly
Demo app:
Bottom right corner:
In the live reactions demo, we stream two types of things:
clients
event: number of clientsdata
event: array of emoji enum values (1-8)< event: clients
< data: 10
< data: [1,2,3,4]
EventSource will reconnect if the connection is interrupted.
Default reconnection timeout ~ 3-5 s.
The reconnection timeout can be customized.
Emit a retry:
field in any of the events:
< retry: 2500
< data: Hello!\n\n
Playground: “Retry-flaky” scenario
Events can include an id
field with any UTF-8 string as value
Connection interrupted? Sets reconnection header Last-Event-ID: x
< id: data-0
< retry: 5000
< data: Data Zero event\n
💔 Disconnects ➡️ 5 seconds later
> GET /stream/notifications
> Last-Event-ID: data-0
Playground: “notifications” scenario
Entire SSE gramar: 4+1 fields
retry: 2000
id: 0
data: Hello\n\n
:I am a comment
event: status
You can subscribe to custom events with .addEventListener
:
Subscribe to open
and error
for connection management:
constructor(url, { withCredentials })
withCredentials: boolean
use CORS credentials (default: false)open
| error
| message
| <custom-name>
close()
readyState
: State intent enum: CONNECTING
(0) | OPEN
(1) | CLOSED
(2)
useEffect
or a custom hook useEffect(() => {
const eventSource = new EventSource(` http://localhost:3001/stream/${endpoint}` );
// connection mgmt
eventSource.addEventListener('open', () => console.log("Got open"));
eventSource.addEventListener('error', () => console.log("Got error"));
// data callbacks
eventSource.addEventListener('message', () => console.log("Got message"));
eventSource.addEventListener('custom', () => console.log("Got custom"));
// destroy when unloaded
return () => eventSource.close();
}, []);
I hold no $SSE stock
will not be made available
idk u
Warts and all
I ate some dog food for you science
Single bit of information: “error”
callback signature is (event: Event) => void
event.target
is instanceof EventSource
readyState
to find out EventSource’s intent:
Max number of connections: 6
Per-hostname quota
Browser-wide enforcement (shared by all tabs)
Too much SSE without planning -> choke
When a network error is encountered:
Test it out in the playground repo:
A server can signal “do not reconnect”:
Content-Type
header other than text/event-stream
Playground: “Not SSE” scenario
Important payload?
Consider handling reconnections explicitly
onerror
-> evtSrc.close(); setTimeout() ...
Some proxies dislike idle connections & will kill them quickly. Fix(es):
You can emit a comment
< :)
Good enough to keep connection alive.
EventSource won’t emit any event.
Some proxies dislike idle connections & will kill them quickly. Fix(es):
Emit a custom event every ~15 seconds:
< event: heartbeat
< data: ""
(data field must be present)
Use it to detect stale connections: “expect heartbeats every N seconds, otherwise reconnect”
Firefox has yet to implement support for EventSource in its Service Worker context.
Future people can track the present validity of this statement here.
✅ But you can use it in a SharedWorker
whois
“Kadena”Scalabe PoW Blockchain: Chainweb
20x braided chains
Blockchain stuff usually comes with lots of polling. E.g. determining finality
Kadena’s Chainweb is 20 “braided” chains -> 20x polling threads (worst case)
Presentation source & SSE playground - Github
Chainweb-Stream-Client / interesting part
§ 9.1 MessageEvent Interface - HTML Living Standard
§ 9.2 Server-Sent Events - HTML Living Standard
MDN - Server-Sent Events · EventSource
Monospace font:
Kode mono by Kadena’s Isa Ozler
Comments
Any lines starting with
:
(colon)These are ignored on the client-side