Add the sse-websocket module
This commit is contained in:
81
sse-websocket/docs/01-two-protocols.md
Normal file
81
sse-websocket/docs/01-two-protocols.md
Normal file
@@ -0,0 +1,81 @@
|
||||
# 1. Two protocols, one question
|
||||
|
||||
Next: [2. The SSE lifecycle](02-sse-lifecycle.md)
|
||||
|
||||
---
|
||||
|
||||
Server-Sent Events and WebSocket get compared as if they were rivals for the same job. They are
|
||||
not. The question that separates them is much smaller than "which is better", and it is this:
|
||||
|
||||
> **Does the client need to send anything after the first request?**
|
||||
|
||||
If the answer is no — a dashboard, a progress bar, a notification feed, a log tail, a
|
||||
"your export is ready" ping — SSE is the whole answer, and it is a return type rather than a
|
||||
subsystem. If the answer is yes, and the messages are frequent or need routing between clients,
|
||||
you want WebSocket, and almost certainly STOMP on top of it.
|
||||
|
||||
Everything else in the comparison follows from that one asymmetry.
|
||||
|
||||
## What each one costs you to set up
|
||||
|
||||
| | SSE | STOMP over WebSocket |
|
||||
|---|---|---|
|
||||
| Dependency | `spring-boot-starter-webmvc` | `spring-boot-starter-websocket` |
|
||||
| Auto-configuration involved | none | `spring-boot-websocket` |
|
||||
| Server-side surface | a handler method returning `SseEmitter` | `@EnableWebSocketMessageBroker`, a configurer, a broker, a converter stack |
|
||||
| Transport | one long-lived HTTP response | an HTTP/1.1 Upgrade to a framed, bidirectional connection |
|
||||
| Client | `new EventSource(url)`, built into every browser | a STOMP library |
|
||||
| Reconnect | automatic, with `Last-Event-ID` | yours to write |
|
||||
| Server knows who is connected | no | yes — `SimpUserRegistry`, connect/subscribe/disconnect events |
|
||||
| Payload | UTF-8 text only | text or binary |
|
||||
|
||||
The dependency line is the Boot 4 detail worth stating out loud. `spring-boot-starter-websocket`
|
||||
pulls in `spring-boot-websocket`, which is where the auto-configuration lives. Depending on
|
||||
`org.springframework:spring-websocket` and `spring-messaging` directly compiles and starts, and
|
||||
then nothing works — the same rule that catches people with `spring-kafka` in
|
||||
[`../kafka-basics`](../kafka-basics/README.md) and `spring-rabbit` in
|
||||
[`../rabbitmq`](../rabbitmq/README.md). In Boot 4, **depending on a library rather than on its
|
||||
Boot starter means you are missing its auto-configuration.**
|
||||
|
||||
## What SSE is not
|
||||
|
||||
Two things people assume, both wrong, both measured in this module:
|
||||
|
||||
**"It pins a thread per client."** It does not. `SseEmitter` switches the request to asynchronous
|
||||
mode; the request thread goes back to the pool immediately and the response stays open with
|
||||
nothing attached to it. [`SseConcurrencyTest`](../src/test/java/com/ankurm/ssews/SseConcurrencyTest.java)
|
||||
holds forty streams open against a connector whose pool is capped at ten:
|
||||
|
||||
```
|
||||
emitters open : 40
|
||||
connector pool size : 10 (max 10)
|
||||
connector active : 0
|
||||
```
|
||||
|
||||
**"You have to pass a media type or it calls `toString()`."** Also not true, and the opposite is
|
||||
closer to it. See [3. The payload](03-the-payload.md).
|
||||
|
||||
## What SSE genuinely cannot do
|
||||
|
||||
- **Take input.** `EventSource` issues one GET and never sends again. Client-to-server traffic has
|
||||
to go over ordinary HTTP requests, which is fine for low rates and awful for a chat.
|
||||
- **Send custom headers.** The browser's `EventSource` has no header API, so bearer-token
|
||||
authentication needs a cookie or a query parameter. `withCredentials` exists; `Authorization`
|
||||
does not.
|
||||
- **Carry binary.** The format is line-oriented UTF-8. Binary means base64, which costs a third.
|
||||
- **Tell you a client left.** There is no disconnect event, only a write that fails later —
|
||||
see [2. The SSE lifecycle](02-sse-lifecycle.md).
|
||||
- **Escape the browser's per-origin connection limit.** Over HTTP/1.1 a browser allows about six
|
||||
concurrent connections to one origin, and an open SSE stream is one of them, *per tab*. Four
|
||||
tabs of a dashboard is 4 streams; six is a hung site. HTTP/2 multiplexes and the limit
|
||||
effectively disappears, which makes "do we serve this over HTTP/2?" a real part of the decision.
|
||||
|
||||
## What STOMP costs
|
||||
|
||||
A broker, a message-converter stack, a session registry, an origin policy, and a set of routing
|
||||
rules whose defaults are not what you would guess. Chapters
|
||||
[4](04-stomp.md) and [5](05-limits.md) are that list.
|
||||
|
||||
---
|
||||
|
||||
Next: [2. The SSE lifecycle](02-sse-lifecycle.md)
|
||||
Reference in New Issue
Block a user