Real-Time & Async Operations
When request/response stops fitting: WebSocket message contracts, SSE, streaming, the async job pattern for long-running work, and how completion actually reaches the client.
Every lesson below names the consumers, the design question and the guarantee before recommending anything. Recommendations come with what they cost, when not to use them, and how they evolve.
A WebSocket gives you a pipe, not a protocol. Everything HTTP provided for free — operations, status codes, request/response pairing — you must now design: typed message envelopes, acks, errors, sequence numbers, and a reconnect story clients can actually implement.
One long-lived HTTP response, streaming events one way: server to client. SSE buys auto-reconnect with built-in resume (Last-Event-ID) for the price of unidirectionality — and for notifications, progress, dashboards and token streams, one way is all you needed.
A streamed response is a sequence of commitments, not one answer. The contract must say what each chunk means, whether early chunks can be trusted before the end, how the stream announces failure mid-flight, and what a consumer resumes after a drop.
A request that takes 15 minutes cannot pretend to be request/response — some timeout between the client and your handler will fire first, and a retry starts the 15 minutes again. Return 202 with a job resource instead, and the operation becomes observable, retry-safe and cancellable.
POST the operation, get 202 and a job resource, let a worker do the work, poll or be notified, fetch the result. The pattern is simple; the contract is not — queued/running/succeeded/failed/cancelled is a state machine with retention, cancellation, progress and idempotent creation that consumers build whole workflows on.
Polling, webhooks, SSE/WebSocket, push notification — four ways to say "done", each with a different latency, infrastructure cost, client requirement and duplicate story. Polling with Retry-After is the documented baseline every client can use; the others are upgrades for specific consumers.
A streaming or download API produces bytes faster than some consumer can take them. Where do the bytes wait, who runs out of memory first, and when does the server hang up? A contract that does not answer those questions answers them in production — usually by the whole tier falling over together.