Unary vs Streaming RPCs — Client, Server, Bidi & Backpressure
gRPC RPCs are not only request/response. Four shapes — unary, server-streaming, client-streaming, bidirectional — change memory, latency, and failure modes. Senior interviews ask when each fits, how HTTP/2 flow control provides backpressure, and which anti-patterns (unbounded server streams, ignoring cancel) blow up production.
- 1Gist
- 2Maps
- 3Q&A
- 4Sandbox
Voice readout needs Web Speech Synthesis in this browser.
How the bytes should leave the process
Prefer
Match the shape to memory and latency
Unary for CRUD. Server-stream for multi-GB or live feeds. Client-stream for uploads. Bidi only when you truly need duplex. HTTP/2 windows plus app-level bounds keep a slow consumer from pinning RAM.
- Streaming is multiple messages over time with flow control — not a repeated field in one message.
- Honor cancel mid-stream so handlers stop producing.
- Bidi needs sticky LB so the stream is not reset mid-flight.
Alternative
One huge unary, or a send-forever stream
A giant unary blob OOMs both sides. An unbounded server stream with no deadline pins memory on one slow client. Polling unary loops fake duplex and waste QPS.
- Browser without grpc-web: REST / SSE / WebSocket — not raw gRPC.
- Ignoring client cancel wastes CPU after hangup. Depth: deadlines lesson.
- Most retries are unsafe mid-stream — prefer idempotent unary.
Backpressure on a server stream
HTTP/2 windows stop a fast sender. Application code still bounds queues and honors cancel.
- 1
Open stream + request
Client starts the RPC. Server dispatches the handler. - 2
Message 1 delivered
Handler yields; channel frames HTTP/2. - 3
Client slow
Receive window shrinks. Message 2 blocks on flow control. - 4
Window update
Client reads more; Message 2 flows. - 5
Cancel or half-close
Handler must exit. Unbounded produce-forever is the anti-pattern.
Overview
gRPC RPCs are not only request/response. Four shapes change memory, latency, and failure modes. Senior interviews ask when each fits, how HTTP/2 flow control provides backpressure, and which anti-patterns blow up production.
The four shapes
| Type | Client sends | Server sends | Classic fit |
|---|---|---|---|
| Unary | 1 | 1 | GetUser, PlaceOrder |
| Server-stream | 1 | N | Download chunks, event feed |
| Client-stream | N | 1 | Upload, aggregate metrics |
| Bidi | N | N | Chat, live sync, sensors |
When each wins (comparative)
| Need | Prefer | Avoid |
|---|---|---|
| Simple CRUD | Unary | Streaming ceremony |
| Multi-GB download | Server-stream | One huge unary message |
| Upload with progress | Client-stream | Base64 mega-JSON |
| Interactive duplex | Bidi | Polling unary loops |
| Browser without grpc-web | REST/SSE/WebSocket | Raw gRPC |
Backpressure & flow control
HTTP/2 window updates stop a fast sender when the receiver's buffer fills. Application code must still:
- Bound in-memory queues.
- Honor cancellation mid-stream.
- Avoid send-forever without a consumer.
Anti-pattern: server streams with no page token / no deadline / no cancel — one slow client pins memory.
Sequence
- 1
Client → Channel
1 Open stream + request
- 2
Channel → Server
2 Dispatch RPC
- 3
Server → Channel
3 Message 1
- 4
Channel → Client
4 Deliver msg1
- 5
Client
5 Client slow, window shrinks
- 6
Server → Channel
6 Msg2 blocked on window
- 7
Client → Channel
7 Window update
- 8
Channel → Client
8 Message 2 flows
- 9
Client → Channel
9 Cancel or half-close
- 10
Channel → Server
10 Handler exits
Lesson map
Unary vs Streaming RPCs — Client, Server, Bidi & Backpressure
gRPC RPCs are not only request/response. Four shapes — unary, server-streaming, client-streaming, bidirectional — change memory, latency, and failure modes. Senior interviews ask when each fits, how HTTP/2 flow control provides backpressure, and which anti-patterns (unbounded server streams, ignoring cancel) blow up production.
Architecture. Architecture
Select a node to see why it exists, or an edge to see the protocol, direction, effect, and consequence.
Mermaid export
flowchart TB c["Client"] ch["Channel"] s["Server"] c -->|1 Open stream +| ch ch -->|2 Dispatch RPC| s s -->|3 Message 1| ch ch -->|4 Deliver msg1| c s -->|6 Msg2 blocked| ch c -->|7 Window update| ch
Three participants, short labels, lifelines stay in the card.
Anti-patterns
| Anti-pattern | Failure | Fix |
|---|---|---|
| Unbounded server stream | Memory / FD exhaustion | Pagination, deadlines, cancel |
| Giant unary blob | TOCTOU + OOM | Chunk via server/client stream |
| Ignoring client cancel | Wasted CPU after hangup | Propagate context cancellation |
| Bidi without sticky LB | Stream resets on rebalance | Affinity — see LB lesson |
Sandbox: four toy shapes (Python)
Generators stand in for streams. Production gRPC uses iterators / async iterators on the stub.
Press Run. Snippets must be self-contained — no network, files, or native modules.
Same shapes (TypeScript async iterators)
Press Run. Snippets must be self-contained — no network, files, or native modules.
Pitfalls
Do you send one unary bytes field? A client-stream of chunks? Or object-store PUT + unary finalize? What happens when the client cancels at 60%?
Interview Q&A
Unary vs returning repeated in one message?
Answer
repeated is still one RPC message. Streaming is multiple messages over time with flow control.
Does server-stream need HTTP/2?
Answer
gRPC's model assumes HTTP/2 multiplexing; browsers often use grpc-web which may limit streaming.
How does backpressure surface in app code?
Answer
Blocking/async writes wait on flow-control windows; readers must keep consuming.
When is bidi the wrong choice?
Answer
When a simple unary or server-stream suffices — bidi complicates LB affinity and testing.
Upload of a large file?
Answer
Client-stream or separate object-store PUT + unary finalize.
Can you cancel mid-stream?
Answer
Yes — clients cancel; servers should stop producing (see Deadlines lesson).
What is half-close?
Answer
Client finishes sending but still reads (common in client-stream).
Streaming + retries?
Answer
Most retries are unsafe mid-stream; prefer idempotent unary with retry policies. Keys and method truth: idempotency keys and idempotent HTTP methods — do not re-teach the key state machine here.