Lesson 6 · Streaming RPCs

Client streaming

A stream of requests in, one response out — the upload shape.

Your win: explain client streaming, read its Go handler (Recv loop then SendAndClose), and know when it's the right choice — anchored to bob's UploadAsset.

The shape: many requests → 1 response

The mirror image of Lesson 5. The client sends a stream of messages; when it's done, the server returns a single response.1 The stream keyword goes on the request:

proto/bob/v1/media.proto:128
rpc UploadAsset(stream UploadAssetRequest) returns (UploadAssetResponse);

The Go handler: receive until EOF, then respond once

internal/bob/services/media/media_modifier.go:166
func (svc *MediaModifierService) UploadAsset(
        srv bpb.MediaModifierService_UploadAssetServer) error {
    for {
        req, err := srv.Recv()
        if err == io.EOF { break }   // client finished sending
        if err != nil { return err }
        // accumulate this chunk…
    }
    return srv.SendAndClose(&bpb.UploadAssetResponse{...})  // the one response
}
The pattern Only a stream argument — no request, no ctx param (use srv.Context()). Loop srv.Recv() until io.EOF (that's how you learn the client is done — recall io.EOF from the Go course), then finish with one srv.SendAndClose(resp).

When to use it

Client streaming fits when the input is a sequence the server folds into one result: uploading a file in chunks, streaming rows for a bulk import, or aggregating many data points into a summary. You avoid buffering the whole payload in one giant message.

Anchor bob's UploadAsset is our client-streaming shape (file chunks → one asset). Note it's currently a stub returning codes.Unimplemented (media_modifier.go:166) — the signature is the teaching value. A fully-wired example is yasuo's ImportSchools(stream …) (proto/yasuo/v1/imports.proto:66). None of your three services use client streaming — they're unary.
Read / do this next

gRPC — Core concepts (Client streaming) + Go Basics

Core concepts for the lifecycle; the Go Basics tutorial implements a client-streaming method with the Recv-loop-then-SendAndClose pattern.

grpc.io — client streaming
grpc.io — Go basics

Check yourself (from memory)

Q1. In client streaming, the stream keyword is on the…

Many requests → one response, so stream marks the request: (stream Req) returns (Resp).

Q2. A client-streaming Go handler reads requests with…

Loop Recv() until io.EOF, then one SendAndClose(resp). No plain request argument.

Q3. Client streaming suits…

A sequence of inputs folded into one result — uploads, bulk imports, aggregation. That's bob's UploadAsset.
Describe client streaming and its Go handler shape, with a repo example.
recall, then click to reveal
Client sends a STREAM of requests; server returns ONE response when the client finishes (stream on the request). Go handler: func(srv X_Server) error — no request/ctx args; loop req, err := srv.Recv() until io.EOF, accumulate, then srv.SendAndClose(resp). Repo example: bob's UploadAsset (media.proto:128 → media_modifier.go:166, currently a stub) and yasuo's ImportSchools. Good for uploads/batch ingestion.
Curious how the client sends the stream (stream.Send(chunk) then stream.CloseAndRecv())? Ask me.

1. gRPC — Core concepts: client streaming.