Server Streaming RPC
rpc Method(Request) returns (stream Response)Server streaming sends one request and receives a stream of responses. The server sends multiple messages on the same HTTP/2 stream, keeping it open until the response stream is complete. Ideal for large dataset pagination, real-time feed subscriptions, file downloads, and log tailing where the server generates results over time.
Details
Server streaming allows the server to push multiple responses to a single client request: client sends one request → server streams N responses → server closes stream
HTTP/2 mechanics: the client sends one DATA frame (request). The server sends multiple DATA frames (each response message) and finally a HEADERS frame (trailers with Grpc-Status=0 on success).
Backpressure: HTTP/2 window-based flow control ensures the client can receive at its own pace. If the client's receive window is full, the server's write blocks until the client drains the buffer.
Streaming vs pagination: REST pagination: N round trips for N pages (each page is a new HTTP request) gRPC server streaming: 1 round trip, N messages (one HTTP/2 stream, messages arrive as produced) Server streaming has lower latency for sequential consumption because the server starts sending before the full result is ready.
Error handling: if the server encounters an error mid-stream, it sends trailers with a non-zero Grpc-Status. The client receives all messages sent before the error, then gets the error status.
Common patterns: - List a large dataset: stream records as they are queried from the DB - Subscribe to events: server sends new events as they occur - File download: send chunks as file is read from disk - Search results: stream results as the search engine finds them
Proto definition
syntax = "proto3";
service OrderService {
// Stream all orders for a customer (large dataset)
rpc ListOrders(ListOrdersRequest) returns (stream Order);
// Live order status updates
rpc WatchOrderStatus(WatchOrderRequest) returns (stream OrderStatus);
// Stream log entries
rpc TailLogs(TailLogsRequest) returns (stream LogEntry);
}
message ListOrdersRequest { string customer_id = 1; }
message WatchOrderRequest { string order_id = 1; }Python server streaming
# Server (Python)
def ListOrders(self, request, context):
for order in db.query_orders(request.customer_id):
yield order # each yield sends one message to client
if context.is_active() == False:
return # client cancelled, stop sending
# Client (Python)
stream = stub.ListOrders(ListOrdersRequest(customer_id="cust_1"))
for order in stream: # iterate the stream
process(order)
# StopIteration raised when server closes streamWhen to use
Large dataset streaming
Real-time event feeds
Log tailing
Search result streaming
File downloads in chunks
Backpressure
HTTP/2 flow control – server write blocks when client receive window is full. Client processes at its own rate.