Senior · Network services

Retrying a partially consumed gRPC stream

A client receives half a stream, loses the connection and retries the method. What needs to be specified beyond generated stubs?

Try explaining this aloud before opening the answer. State your assumptions and trace a boundary case.

EXAMPLE · FRAGMENT UNLESS A COMPLETE PROGRAM IS SHOWN

go
package main

import (
	"context"
	"fmt"
	"time"

	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

func classify(ctx context.Context) error {
	if err := ctx.Err(); err != nil {
		return status.FromContextError(err).Err()
	}
	return nil
}
func main() {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	cancel()
	err := classify(ctx)
	fmt.Println(status.Code(err) == codes.Canceled) // true, not DeadlineExceeded
}
Reveal a strong answer
  1. Generated Go stubs remove repetitive transport code, not the need to design a distributed operation. A gRPC method can block, partially stream data, be retried or outlive its caller unless the application defines its lifetime. Treat protobuf fields as a versioned wire contract and the RPC method as a budgeted operation with explicit authorization and failure semantics.

  2. Set or propagate deadlines because an RPC has no useful universal business timeout. Bound stream queues, use backpressure and make one goroutine own each send/receive direction according to the API contract. Verify metadata-based identity at the server rather than treating all metadata as trusted. Pin protoc and its Go plugins so generated code can be reproduced. The cancelled context maps to the protocol’s cancellation status. It is not rewritten as a successful empty result or confused with expiration of a deadline. In a real handler, domain errors need a deliberate status mapping that does not reveal internal credentials or SQL text; the client separately decides whether a retry is semantically safe.

  3. Do not reuse removed protobuf field numbers; reserve them and keep old message fixtures. A cancelled stream can already have produced durable effects or partial results. Retrying a stream or RPC requires an application identity and a resume/deduplication policy. Test old/new clients, missing deadlines, a slow peer, mid-stream failure and shutdown. Native gRPC networking is taught here, not added to the iOS guest runtime.

Common trap

Repeating a method call is not necessarily a safe continuation of a partially observed operation.

Try it

Define resume identity, partial-result handling, ordering, duplicate detection, deadlines and compatible protobuf evolution.

Worked solution

Generated stubs do not supply business atomicity or resumability. The operation needs an explicit cursor/identity and ordering/deduplication policy, bounded per-direction ownership and a propagated deadline. Classify cancellation, deadline and domain statuses deliberately. Preserve wire compatibility with reserved removed field numbers and old/new fixtures, and pin the generation tools. Test a slow receiver, mid-stream failure, replay and shutdown with the real transport.

Change the constraint

What differs between a read-only paginated stream and a stream that performs durable writes?

How did you do?

Self-assessment, not a compiler pass or interview score. Explain the reasoning unaided before marking understood.

Not marked. Progress stays on this browser, separate from course completion.

Primary references

Checked 2026-10-28. Use documentation for your pinned runtime, driver and tool version.