golang-grpc

por samber

Fornece diretrizes de uso do gRPC, organização de protobuf e padrões prontos para produção em microsserviços Golang. Use ao implementar, revisar ou depurar servidores/clientes gRPC, escrever arquivos proto, configurar interceptadores, tratar erros gRPC com códigos de status, configurar TLS/mTLS, testar com bufconn ou trabalhar com RPCs de streaming.

npx skills add https://github.com/samber/cc-skills-golang --skill golang-grpc

Persona: You are a Go distributed systems engineer. You design gRPC services for correctness and operability — proper status codes, deadlines, interceptors, and graceful shutdown matter as much as the happy path.

Modes:

  • Build mode — implementing a new gRPC server or client from scratch.
  • Review mode — auditing existing gRPC code for correctness, security, and operability issues.

Dependencies:

  • protoc: brew install protobuf
  • protoc-gen-go: go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
  • protoc-gen-go-grpc: go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

Go gRPC Best Practices

Treat gRPC as a pure transport layer — keep it separate from business logic. The official Go implementation is google.golang.org/grpc.

This skill is not exhaustive. Please refer to library documentation and code examples for more information. Context7 can help as a discoverability platform.

Quick Reference

ConcernPackage / Tool
Service definitionprotoc or buf with .proto files
Code generationprotoc-gen-go, protoc-gen-go-grpc
Error handlinggoogle.golang.org/grpc/status with codes
Rich error detailsgoogle.golang.org/genproto/googleapis/rpc/errdetails
Interceptorsgrpc.ChainUnaryInterceptor, grpc.ChainStreamInterceptor
Middleware ecosystemgithub.com/grpc-ecosystem/go-grpc-middleware
Testinggoogle.golang.org/grpc/test/bufconn
TLS / mTLSgoogle.golang.org/grpc/credentials
Health checksgoogle.golang.org/grpc/health

Proto File Organization

Organize by domain with versioned directories (proto/user/v1/). Always use Request/Response wrapper messages — bare types like string cannot have fields added later. Generate with buf generate or protoc.

Proto & code generation reference

Server Implementation

  • Implement health check service (grpc_health_v1) — Kubernetes probes need it to determine readiness
  • Use interceptors for cross-cutting concerns (logging, auth, recovery) — keeps business logic clean
  • Use GracefulStop() with a timeout fallback to Stop() — drains in-flight RPCs while preventing hangs
  • Disable reflection in production — it exposes your full API surface
srv := grpc.NewServer(
    grpc.ChainUnaryInterceptor(loggingInterceptor, recoveryInterceptor),
)
pb.RegisterUserServiceServer(srv, svc)
healthpb.RegisterHealthServer(srv, health.NewServer())

go srv.Serve(lis)

// On shutdown signal:
stopped := make(chan struct{})
go func() { srv.GracefulStop(); close(stopped) }()
select {
case <-stopped:
case <-time.After(15 * time.Second):
    srv.Stop()
}

Interceptor Pattern

func loggingInterceptor(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
    start := time.Now()
    resp, err := handler(ctx, req)
    log.Printf("method=%s duration=%s code=%s", info.FullMethod, time.Since(start), status.Code(err))
    return resp, err
}

Client Implementation

  • Reuse connections — gRPC multiplexes RPCs on a single HTTP/2 connection; one-per-request wastes TCP/TLS handshakes
  • Set deadlines on every call (context.WithTimeout) — without one, a slow upstream hangs goroutines indefinitely
  • Use round_robin with headless Kubernetes services via dns:/// scheme
  • Pass metadata (auth tokens, trace IDs) via metadata.NewOutgoingContext
conn, err := grpc.NewClient("dns:///user-service:50051",
    grpc.WithTransportCredentials(creds),
    grpc.WithDefaultServiceConfig(`{
        "loadBalancingPolicy": "round_robin",
        "methodConfig": [{
            "name": [{"service": ""}],
            "timeout": "5s",
            "retryPolicy": {
                "maxAttempts": 3,
                "initialBackoff": "0.1s",
                "maxBackoff": "1s",
                "backoffMultiplier": 2,
                "retryableStatusCodes": ["UNAVAILABLE"]
            }
        }]
    }`),
)
client := pb.NewUserServiceClient(conn)

Error Handling

Always return gRPC errors using status.Error with a specific code — a raw error becomes codes.Unknown, telling the client nothing actionable. Clients use codes to decide retry vs fail-fast vs degrade.

CodeWhen to Use
InvalidArgumentMalformed input (missing field, bad format)
NotFoundEntity does not exist
AlreadyExistsCreate failed, entity exists
PermissionDeniedCaller lacks permission
UnauthenticatedMissing or invalid token
FailedPreconditionSystem not in required state
ResourceExhaustedRate limit or quota exceeded
UnavailableTransient issue, safe to retry
InternalUnexpected bug
DeadlineExceededTimeout
// ✗ Bad — caller gets codes.Unknown, can't decide whether to retry
return nil, fmt.Errorf("user not found")

// ✓ Good — specific code lets clients act appropriately
if errors.Is(err, ErrNotFound) {
    return nil, status.Errorf(codes.NotFound, "user %q not found", req.UserId)
}
return nil, status.Errorf(codes.Internal, "lookup failed: %v", err)

For field-level validation errors, attach errdetails.BadRequest via status.WithDetails.

Streaming

PatternUse Case
Server streamingServer sends a sequence (log tailing, result sets)
Client streamingClient sends a sequence, server responds once (file upload, batch)
BidirectionalBoth send independently (chat, real-time sync)

Prefer streaming over large single messages — avoids per-message size limits and lowers memory pressure.

func (s *server) ListUsers(req *pb.ListUsersRequest, stream pb.UserService_ListUsersServer) error {
    for _, u := range users {
        if err := stream.Send(u); err != nil {
            return err
        }
    }
    return nil
}

Testing

Use bufconn for in-memory connections that exercise the full gRPC stack (serialization, interceptors, metadata) without network overhead. Always test that error scenarios return the expected gRPC status codes.

Testing patterns and examples

Security

  • TLS MUST be enabled in production — credentials travel in metadata
  • For service-to-service auth, use mTLS or delegate to a service mesh (Istio, Linkerd)
  • For user auth, implement credentials.PerRPCCredentials and validate tokens in an auth interceptor
  • Reflection SHOULD be disabled in production to prevent API discovery

Performance

SettingPurposeTypical Value
keepalive.ServerParameters.TimePing interval for idle connections30s
keepalive.ServerParameters.TimeoutPing ack timeout10s
grpc.MaxRecvMsgSizeOverride 4 MB default for large payloads16 MB
Connection poolingMultiple conns for high-load streaming4 connections

Most services do not need connection pooling — profile before adding complexity.

Common Mistakes

MistakeFix
Returning raw errorBecomes codes.Unknown — client can't decide whether to retry. Use status.Errorf with a specific code
No deadline on client callsSlow upstream hangs indefinitely. Always context.WithTimeout
New connection per requestWastes TCP/TLS handshakes. Create once, reuse — HTTP/2 multiplexes RPCs
Reflection enabled in productionLets attackers enumerate every method. Enable only in dev/staging
codes.Internal for all errorsWrong codes break client retry logic. Unavailable triggers retry; InvalidArgument does not
Bare types as RPC argumentsCan't add fields to string. Wrapper messages allow backwards-compatible evolution
Missing health check serviceKubernetes can't determine readiness, kills pods during deployments
Ignoring context cancellationLong operations continue after caller gave up. Check ctx.Err()

Cross-References

  • → See samber/cc-skills-golang@golang-context skill for deadline and cancellation patterns
  • → See samber/cc-skills-golang@golang-error-handling skill for gRPC error to Go error mapping
  • → See samber/cc-skills-golang@golang-observability skill for gRPC interceptors (logging, tracing, metrics)
  • → See samber/cc-skills-golang@golang-testing skill for gRPC testing with bufconn

Mais skills de samber

golang-code-style
samber
Golang code style conventions — line length and breaking, variable declarations, control flow clarity, when comments help vs hurt. Use when writing or reviewing Go code, asking about style or clarity, or establishing project coding standards. Not for naming conventions (→ See `samber/cc-skills-golang@golang-naming` skill), linter configuration (→ See `samber/cc-skills-golang@golang-lint` skill), or doc comments (→ See `samber/cc-skills-golang@golang-documentation` skill).
developmentcode-review
golang-testing
samber
Production-ready Golang tests — table-driven tests, testify suites and mocks, parallel tests, fuzzing, fixtures, goroutine leak detection with goleak, snapshot testing, code coverage, integration tests, idiomatic test naming. Use when writing or reviewing Go tests, choosing a testing approach, setting up Go test CI, or debugging flaky/slow tests. For testify-specific APIs see `samber/cc-skills-golang@golang-stretchr-testify`; for measurement methodology see...
developmenttestingcode-review
golang-design-patterns
samber
Padrões de design idiomáticos em Golang — opções funcionais, construtores, fluxo e cascata de erros, gerenciamento e ciclo de vida de recursos, desligamento gracioso, resiliência, arquitetura, injeção de dependência, manipulação de dados, streaming e mais. Aplicar ao escolher explicitamente entre padrões arquiteturais, implementar opções funcionais, projetar APIs de construtores, configurar desligamento gracioso, aplicar padrões de resiliência ou perguntar qual padrão idiomático Go se adequa a um problema específico.
developmentdesigncode-review
golang-error-handling
samber
Idiomatic Golang error handling — creation, wrapping with %w, errors.Is/As, errors.Join, custom error types, sentinel errors, panic/recover, the single handling rule, structured logging with slog, HTTP request logging middleware, and samber/oops for production errors. Built to make logs usable at scale with log aggregation 3rd-party tools. Apply when creating, wrapping, inspecting, or logging errors in Go code. For samber/oops specifics → See `samber/cc-skills-golang@golang-samber-oops`...
developmentcode-review
golang-performance
samber
Padrões e metodologia de otimização de desempenho em Golang - se gargalo X, então aplique Y. Abrange redução de alocação, eficiência de CPU, layout de memória, ajuste de GC, pooling, caching e otimização de hot-path. Use quando profiling ou benchmarks identificaram um gargalo e você precisa do padrão de otimização correto para corrigi-lo. Use também ao realizar revisão de código de desempenho para sugerir melhorias ou benchmarks que possam ajudar a identificar ganhos rápidos de desempenho. Não é para metodologia de medição (→...
developmentcode-review
golang-security
samber
Práticas recomendadas de segurança e prevenção de vulnerabilidades para Golang. Aborda injeção (SQL, comando, XSS), criptografia, segurança de sistema de arquivos, segurança de rede, cookies, gerenciamento de segredos, segurança de memória e registro. Aplicar ao escrever, revisar ou auditar código Go para segurança, ou ao trabalhar em qualquer código arriscado envolvendo criptografia, E/S, gerenciamento de segredos, manipulação de entrada do usuário ou autenticação. Inclui configuração de ferramentas de segurança.
securitycode-reviewdevelopment
golang-database
samber
Guia abrangente para acesso a banco de dados em Go — consultas parametrizadas, escaneamento de structs, colunas anuláveis, transações, níveis de isolamento, SELECT FOR UPDATE, pool de conexões, processamento em lote, propagação de contexto e ferramentas de migração. Use ao escrever, revisar ou depurar código Golang que interage com PostgreSQL, MariaDB, MySQL ou SQLite; para testes de banco de dados; ou para dúvidas sobre database/sql, sqlx ou pgx. NÃO gera esquemas de banco de dados ou SQL de migração.
developmentdatabase
golang-lint
samber
Melhores práticas de linting e configuração do golangci-lint para projetos Golang — execução de linters, configuração do .golangci.yml, supressão de avisos com diretivas nolint, interpretação da saída de lint e seleção de linters. Use ao configurar o golangci-lint, ao perguntar sobre avisos de lint ou supressões nolint, ao configurar ferramentas de qualidade de código ou ao escolher linters. Use também quando o usuário mencionar golangci-lint, go vet, staticcheck ou revive.
developmentcode-reviewtesting