Go gRPC (Production)
Overview
gRPC provides strongly-typed RPC APIs backed by Protocol Buffers, with first-class streaming support and excellent performance for service-to-service communication. This skill focuses on production defaults: versioned protos, deadlines, error codes, interceptors, health checks, TLS, and testability.
Quick Start
1) Define a versioned protobuf API
✅ Correct: versioned package
❌ Wrong: unversioned package (hard to evolve)
2) Generate Go code
Install generators:
Generate:
3) Implement server with deadlines and status codes
✅ Correct: validate + map errors to gRPC codes
❌ Wrong: return raw errors (clients lose code semantics)
Core Concepts
Deadlines and cancellation
Make every call bounded; enforce server-side timeouts for expensive handlers.
✅ Correct: require deadline
Metadata
Use metadata for auth/session correlation, not for primary request data.
✅ Correct: read auth token from metadata
Interceptors (Middleware)
Use interceptors for cross-cutting concerns: auth, logging, metrics, tracing, request IDs.
✅ Correct: unary interceptor with request ID
Streaming patterns
Server streaming (paginate or stream results)
✅ Correct: stop on ctx.Done()
Unary vs streaming decision
- Use unary for single request/response and simple retries.
- Use server streaming for large result sets or continuous updates.
- Use client streaming for bulk uploads with one final response.
- Use bidirectional streaming for interactive protocols.
Production Hardening
Health checks and reflection
Add health service; enable reflection only in non-production environments.
✅ Correct: health + conditional reflection
Graceful shutdown
Prefer GracefulStop with a deadline.
✅ Correct: graceful stop
TLS
Use TLS (or mTLS) in production; avoid insecure credentials outside local dev.
✅ Correct: server TLS
Testing (bufconn)
Test gRPC handlers without opening real sockets using bufconn.
✅ Correct: in-memory gRPC test server
Anti-Patterns
-
Ignore deadlines: unbounded handlers cause tail latency and resource exhaustion.
-
Return string errors: map domain errors to
codes.*withstatus.Errororstatus.Errorf. -
Stream without backpressure: stop on
ctx.Done()and handleSenderrors. -
Expose reflection in production: treat reflection as a discovery surface.
Troubleshooting
Symptom: clients see UNKNOWN errors
Actions:
- Return
status.Error(codes.X, "...")instead of raw errors. - Wrap domain errors into typed errors, then map to gRPC codes.
Symptom: slow/hanging requests
Actions:
- Require deadlines and propagate
ctxto downstream calls. - Add server-side timeouts and bounded concurrency in repositories.
Symptom: flaky streaming
Actions:
- Stop streaming on
ctx.Done()and handlestream.Senderrors. - Avoid buffering entire result sets before sending.
Resources
- gRPC Go: https://github.com/grpc/grpc-go
- Protobuf Go: https://pkg.go.dev/google.golang.org/protobuf
- gRPC error codes: https://grpc.io/docs/guides/error/


