blob: 383bc7956071a0c404766899e328cdb41e86b878 [file] [view]
# Streaming & Push Transports
**Audience:** application developers choosing how subscribers receive events
(pull vs push), and builders of LLM-style streaming workloads. Covers
long-poll, SSE, WebSocket, and the two streaming-session modes.
---
## Choosing a transport
| Transport | Endpoint | Direction | Port | Best for |
| --- | --- | --- | --- | --- |
| **HTTP long-poll** | `GET /events/poll` | client-driven | 10105 | Batch consumers, scheduled jobs, serverless; NAT-friendly |
| **SSE** | `GET /events/stream` | server push (one-way) | 10105 | Browser/mobile push, dashboards, LLM token streams |
| **WebSocket** | WS upgrade on the dedicated port | server push, bi-directional | 10107 (opt-in) | Low-latency interactive clients |
All three deliver identical CloudEvent payloads and share the same ACK /
retry / quota machinery — the only difference is the push direction.
## Long-poll
```shell
curl "http://localhost:10105/events/poll?clientId=order-svc&timeoutMs=30000"
# → [{ "deliveryId": "...", "event": { ...CloudEvent... } }, ...]
```
Batches up to `max` (default 100) buffered events; blocks up to
`timeoutMs`. The SDK wraps this in a background loop:
`client.subscribe("orders", "LOAD_BALANCE", handler)`.
## SSE
```shell
curl -N "http://localhost:10105/events/stream?clientId=order-svc" \
-H "Accept: text/event-stream"
```
The runtime holds the response open and writes `data: <CloudEvent JSON>`
frames as events arrive. Write failures nack the dispatcher immediately
(the event is re-dispatched rather than lost to a dead connection). SDK:
`client.subscribeSse(topic, mode, handler)`.
## WebSocket
The WS server is a separate port (`-Deventmesh.ws.port=10107`, disabled by
default) because the upgrade handshake is a different protocol negotiation.
The **client must configure `wsUrl` explicitly** — pointing it at the HTTP
port fails the handshake:
```java
CloudEventsClient wsClient = CloudEventsClient.builder()
.runtimeUrl("http://localhost:10105") // publish / long-poll / SSE
.wsUrl("http://localhost:10107") // WS push
.clientId("ws-sub").build();
wsClient.subscribeWs("orders", "BROADCAST", event -> { ... });
```
## LLM streaming (Mode 1 / Mode 2)
EventMesh provides two streaming patterns for LLM-style workloads — token
chunks flowing back, multi-turn conversation context — built on the session
layer (`eventmesh-runtime/.../session/`, `SessionRouter`).
| Mode | Use case | Direction | Entry |
| --- | --- | --- | --- |
| **Mode 1** — streaming call | client → agent (LLM), agent streams tokens back | request/response with push | `client.streaming().openSession(...)` |
| **Mode 2** — session pub/sub | producer writes chunks; consumers read via SSE | publish/subscribe | `client.subscribeSession(sessionId)` / `openSessionPublisher(sessionId)` |
### Mode 1 — single streaming call
```java
try (StreamingResponse r = client.streaming()
.openSession(OpenSession.builder().clientId(client.clientId()).build())
.call("Summarize this document…",)) {
while (r.hasNext()) {
System.out.print(r.next().text());
}
}
```
### Mode 2 — session pub/sub
```java
try (SessionPublisher pub = client.openSessionPublisher(sessionId)) {
pub.publish(chunkEvent); // consumers on subscribeSession() receive via SSE
}
client.subscribeSession(sessionId, chunk -> render(chunk));
```
> The v2 streaming session layer is **not auto-wired** into the default
> bootstrap: an embedder builds it via the session builders
> (`withAgentRegistrar` / `withMatchmaker` / `withSessionRouter`) before
> `start()` — the channel strategy is an explicit embedder choice. See
> [Deployment → deployment modes](deployment.md#deployment-modes).
Load balancing for sessions uses the **sticky recommendation** model: the
runtime's `LoadMeter` self-reports load and `/session/recommend` pins a
client to an instance; instances never forward each other's session traffic.
## Where the code lives
| Piece | Location |
| --- | --- |
| SSE / WS connections | `eventmesh-runtime/.../push/SseConnection.java`, `WsConnection.java` |
| Push pump (nack on failure) | `eventmesh-runtime/.../push/ConnectionPushPump.java` |
| Long-poll channel | `eventmesh-runtime/.../push/LongPollingChannel.java` |
| WS server | `eventmesh-runtime/.../http/UniWsServer.java` |
| Session routing | `eventmesh-runtime/.../session/SessionRouter.java`, `Matchmaker.java` |
| Load meter | `eventmesh-runtime/.../ingress/LoadMeter.java` |
| SDK streaming | `eventmesh-sdks/.../cloudevents/stream/*` |
| Tests | `StreamingSdkE2ETest`, `LiteStreamCallIntegrationTest`, `WebSocketPushIntegrationTest`, `TlsIntegrationTest` |