SSE and websockets
Server-sent events
The SSE events consumer takes the options of the HTTP consumer, and:
- names each event after its
type(event:), and gives every line of the data its owndata:field - sends a
: keep-alivecomment every 15 seconds without events (heartbeat=<millis>,0to stop) - gives each event an
id: - answers with
Cache-Control: no-cacheandX-Accel-Buffering: no, so that no proxy holds the events
id: kafka:eyJvcmRlcnM6MCI6IjQyIn0
event: com.acme.order.created
data: {"specversion":"1.0","id":"...","source":"/shop","type":"com.acme.order.created","data":{"order":42}}
Resuming
On Kafka, Redis streams, Pulsar and RabbitMQ streams, the id of an event holds the positions read so
far, on every partition, stream or topic. A client coming back with it in Last-Event-ID (what a
browser's EventSource does by itself) resumes right after what it got:
const events = new EventSource('https://events.example.com/?x-ca-event-broker-opts-from=earliest');
events.addEventListener('com.acme.order.created', (e) => console.log(JSON.parse(e.data)));
A partition the client got nothing from yet starts where the call asks to start (from): the same
URL, again, as EventSource does. In a group (Kafka, Redis streams), the group knows where it is: the
position is not used. Elsewhere, the id is the id of the event.
Websockets
The Websocket Ingester/Consumer has an in and an out configuration, each one a plugin
configuration (either can be left without a ref):
{
"in": { "ref": "connection_...", "options": { "topic": "commands" } },
"out": { "ref": "connection_...", "options": { "topic": "updates", "group": "ui" } }
}
- Frames sent by the client are published, one at a time. A text frame holding a structured
CloudEvent is that event; anything else is the data of a new one. With
publish_results=true(onin), every frame published is answered with its result. - Events consumed are sent as frames, in the
formatasked for. - With
acks=client(onout), an event is acked only when the client answers{"ack": "<event id>"}(or a list of ids), and no more thanmax_in_flight(100) wait for their ack. Withdelivery=at-least-once, what the client did not ack is delivered again.
Each side follows the policy of its own configuration: a caller option is refused only if no side that takes it allows it.