golang-grpc

от samber

Предоставляет рекомендации по использованию gRPC, организации protobuf и шаблоны для production-ready микросервисов на Golang. Используйте при реализации, ревью или отладке gRPC-серверов/клиентов, написании proto-файлов, настройке перехватчиков, обработке ошибок gRPC с кодами статуса, конфигурации TLS/mTLS, тестировании с bufconn или работе с потоковыми RPC.

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

Больше skills от 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
Идиоматические шаблоны проектирования Golang — функциональные опции, конструкторы, обработка ошибок и каскадирование, управление ресурсами и жизненным циклом, корректное завершение работы, отказоустойчивость, архитектура, внедрение зависимостей, работа с данными, стриминг и другое. Применяйте при осознанном выборе между архитектурными шаблонами, реализации функциональных опций, проектировании API конструкторов, настройке корректного завершения работы, применении шаблонов отказоустойчивости или при выборе идиоматического шаблона Go для конкретной задачи.
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
Шаблоны и методология оптимизации производительности Golang — если узкое место X, примени Y. Охватывает снижение аллокаций, эффективность CPU, компоновку памяти, настройку GC, пулинг, кэширование и оптимизацию горячих путей. Используйте, когда профилирование или бенчмарки выявили узкое место и вам нужен правильный шаблон оптимизации для его устранения. Также используйте при проведении код-ревью производительности, чтобы предложить улучшения или бенчмарки, которые помогут выявить быстрые выигрыши в производительности. Не для методологии измерений (→...
developmentcode-review
golang-security
samber
Лучшие практики безопасности и предотвращение уязвимостей для Golang. Охватывает инъекции (SQL, командные, XSS), криптографию, безопасность файловой системы, сетевую безопасность, куки, управление секретами, безопасность памяти и логирование. Применяется при написании, рецензировании или аудите Go-кода на безопасность, а также при работе с любым рискованным кодом, связанным с криптографией, вводом-выводом, управлением секретами, обработкой пользовательского ввода или аутентификацией. Включает настройку инструментов безопасности.
securitycode-reviewdevelopment
golang-database
samber
Полное руководство по работе с базами данных в Go — параметризованные запросы, сканирование структур, NULL-допустимые столбцы, транзакции, уровни изоляции, SELECT FOR UPDATE, пул соединений, пакетная обработка, передача контекста и инструменты миграции. Используйте при написании, ревью или отладке Golang-кода, взаимодействующего с PostgreSQL, MariaDB, MySQL или SQLite; для тестирования баз данных; или по вопросам, связанным с database/sql, sqlx или pgx. НЕ генерирует схемы баз данных или SQL-миграции.
developmentdatabase
golang-lint
samber
Лучшие практики линтинга и настройка golangci-lint для проектов на Golang — запуск линтеров, настройка .golangci.yml, подавление предупреждений с помощью директив nolint, интерпретация вывода линтера и выбор линтеров. Используйте при настройке golangci-lint, вопросах о предупреждениях линтера или подавлении nolint, настройке инструментов качества кода или выборе линтеров. Также используйте, когда пользователь упоминает golangci-lint, go vet, staticcheck или revive.
developmentcode-reviewtesting