Skip to Content
Quick reference

Quick reference

Одностраничная шпаргалка: именные соглашения, стандартные env-переменные, статусы HTTP → sentinel, Kafka topic naming, типовые метрики. Это не первоисточник — за деталями ходи в соответствующие conventions/. Эта страница — для «быстро напомнить формат».

Содержание

HTTP status → sentinel → code

Полный маппинг — в conventions/http-api.

Service sentinelHTTPResponse code
service.ErrNotFound404not_found
service.ErrValidation400invalid_input
service.ErrUnauthorized401unauthorized
service.ErrForbidden403forbidden
service.ErrConflict409conflict
service.ErrRateLimit429rate_limited
default (unknown)500internal

Правила:

  • Никаких http.StatusX прямо в handler’е — только через mapServiceError.
  • 4xx — клиент виноват, retry не поможет (кроме 429).
  • 5xx — сервис виноват, retry имеет смысл (см. patterns/retry-and-circuit-breaker).

Kafka: topic naming

Формат: kazmaps.<service>.<entity> (per-entity). Действие — в заголовке Event-Type, не в имени топика. Ключ записи = id сущности.

kazmaps.user.account # Event-Type: account.registered/banned/... kazmaps.user.push_token kazmaps.review.review # Event-Type: review.created/updated/deleted/replied kazmaps.media.photo # Event-Type: photo.uploaded/deleted/tagged kazmaps.catalog.place kazmaps.indoor.building
  • <service> — publisher-сервис (owner).
  • <entity> — существительное, единственное число.
  • Действие в Event-Type, прошедшее время: created, updated, deleted, approved, banned, …
  • DLQ: <topic>.dlq. Пример: kazmaps.review.review.dlq.

Подробно — conventions/events.

Kafka: envelope metadata

Обязательные поля в Message.Metadata:

ПолеПример
Event-Typereview.created
Schema-Version"1"
Correlation-IdULID
Source-Servicereview
Published-AtRFC3339Nano
traceparentW3C trace context

Message.UUID — отдельно (не в metadata), ULID, уникален per-сообщение.

Собирается через eventmeta.New(ctx, Envelope{...}). Никаких ручных msg.Metadata.Set(...).

Consumer-group naming

Формат: <service>-<handler>.

notification-on-review-created notification-on-user-banned review-on-moderation-approved search-index-on-review-updated
  • Никаких обобщённых имён (consumer, default, main).
  • Один consumer-group — один handler. Два handler’а на разные топики в одном сервисе → две отдельные group.
  • При rename handler’а имя group меняется → consumer начинает с latest offset’а (см. config). Думай заранее.

Метрики: naming и suffix’ы

Формат: <domain>_<action>_<unit>, snake_case.

SuffixТипПример
_secondsHistogramkafka_publish_duration_seconds
_bytesHistogrammedia_upload_bytes
_totalCounteruser_registrations_total
_ratioGauge (0..1)cache_hit_ratio
(no suffix)Gauge (состояние)outbox_unpublished_rows

Примеры:

http_request_duration_seconds # histogram, стандарт http_requests_total # counter, стандарт user_registrations_total # counter, бизнес-событие kafka_consumer_lag # gauge, current - committed outbox_forwarder_lag_seconds # histogram outbox_unpublished_rows # gauge circuit_breaker_state # gauge: 0/1/2 (Closed/HalfOpen/Open) circuit_breaker_trips_total # counter events_published_total # counter events_consumed_total # counter messages_poisoned_total # counter (DLQ)

Подробнее — conventions/observability.

Env-переменные: префиксы и дефолты

Префикс env-переменных — имя сервиса uppercase. Пример для review:

REVIEW_HTTP_ADDR=:8007 REVIEW_DB_DSN=postgres://... REVIEW_DB_POOL_MIN=2 REVIEW_DB_POOL_MAX=20 REVIEW_REDIS_ADDR=redis:6379 REVIEW_KAFKA_BROKERS=kafka:9092 REVIEW_INTERNAL_API_TOKEN=... REVIEW_GATEWAY_HMAC_KEY=... REVIEW_LOG_LEVEL=info REVIEW_OTEL_EXPORTER_OTLP_ENDPOINT=tempo:4317

Стандартные группы:

ПрефиксЧто содержит
<SVC>_HTTP_ADDR, READ_TIMEOUT, WRITE_TIMEOUT
<SVC>_DB_DSN, POOL_MIN, POOL_MAX
<SVC>_REDIS_ADDR, PASSWORD, DB
<SVC>_KAFKA_BROKERS, CLIENT_ID
<SVC>_INTERNAL_API_TOKEN
<SVC>_GATEWAY_HMAC_KEY
<SVC>_LOG_LEVEL, FORMAT
<SVC>_OTEL_OTLP_ENDPOINT, SAMPLE_RATE
<SVC>_RATE_LOGIN_PER_MIN, UPLOAD_PER_HOUR

Подробно — conventions/configuration.

pgx: частые паттерны

Single row:

err := pool.QueryRow(ctx, q, id).Scan(&u.ID, &u.Email) if err != nil { if pkgdb.IsNoRows(err) { return nil, pkgdb.ErrNotFound } return nil, fmt.Errorf("get user: %w", err) }

Multiple rows:

rows, err := pool.Query(ctx, q, placeID) if err != nil { return nil, fmt.Errorf("query: %w", err) } defer rows.Close() for rows.Next() { var r domain.Review if err := rows.Scan(&r.ID, &r.Rating, &r.Text); err != nil { return nil, fmt.Errorf("scan: %w", err) } out = append(out, r) } return out, rows.Err()

Batch:

batch := &pgx.Batch{} for _, id := range ids { batch.Queue(`UPDATE ... WHERE id = $1`, id) } br := pool.SendBatch(ctx, batch) defer br.Close() for range ids { if _, err := br.Exec(); err != nil { return err } }

Транзакция:

err := s.db.InTx(ctx, func(tx pgx.Tx) error { if err := s.repo.CreateTx(ctx, tx, ...); err != nil { return err } return s.outboxPub.PublishTx(ctx, tx, "outbox", msg) })

Подробно — conventions/db-pgx.

Файловая раскладка сервиса

cmd/server/main.go — wiring всех зависимостей internal/ ├── config/ — envconfig, DSN сборка ├── handler/ — HTTP-handler'ы + router.go ├── middleware/ — gatewayAuth, internalToken, rateLimit ├── service/ — бизнес-логика, sentinel ошибки ├── repository/postgres/ — pgx-репозитории (голый SQL) ├── event/ — publisher, subscriber, handlers ├── domain/ — типы предметной области ├── log/ — slog-wrapper, FromCtx, PII-маскер ├── metrics/ — prometheus registry, MustRegister() ├── otel/ — setup tracer provider └── health/ — /healthz, /readyz handler'ы pkg/ ├── db/ — pgxpool wrapper, InTx, ErrNotFound ├── httpclient/ — RetryClient, CircuitBreaker ├── eventmeta/ — envelope-builder, helper New() └── pii/ — маскирование email/phone для логов migrations/ — golang-migrate up/down

Подробно — conventions/project-layout.

Логирование: обязательные поля

В каждой строке лога:

ПолеЗначение
service"review"
levelinfo, warn, error (не debug в prod)
timeRFC3339Nano
request_idиз X-Request-Id header’а
correlation_idиз X-Correlation-Id или родителя
trace_idпри активном OTel-span
user_idесли authenticated
routeпаттерн (/v1/reviews/{id})

Нельзя в логах: полный email, phone, Authorization header, JWT, password, токены, payment-details. Маскируй через pkg/pii/.

Подробно — conventions/logging.

Таймауты

Типовые значения:

КомпонентTimeout
HTTP server ReadHeaderTimeout10s
HTTP server ReadTimeout30s
HTTP server WriteTimeout60s
HTTP server IdleTimeout120s
chi Timeout middleware30s
Outbound HTTP-client Timeout5–10s
Postgres statement_timeout30s (через env)
Redis op timeout1s
Kafka producer Timeout10s
Kafka consumer session.timeout.ms45–60s
Kafka consumer max.poll.interval.ms300s (не маскировать медленный handler)

Всегда есть ctx.Done() — handler обязан уважать.

Correlation IDs

Три ID, связывающие сигналы в один запрос:

IDHeaderГде ещё
request_idX-Request-Idставит chimw.RequestID, per-request
correlation_idX-Correlation-IdULID, переживает цепочку HTTP→Kafka→HTTP
trace_idtraceparent (W3C)OpenTelemetry span context

В логи кладутся все три. В Tempo span автоматически получает trace_id. В Kafka envelope — Correlation-Id и traceparent.

Makefile targets

В каждом сервис-репо:

TargetЧто делает
make bootstrap.env + go mod download + compose up + миграции
make updocker compose up -d
make downdocker compose down (volumes сохраняются)
make cleandocker compose down -v (чистый старт)
make rebuilddocker compose build && up -d
make logsdocker compose logs -f <service>
make migrate-upmigrate up
make migrate-downmigrate down 1 (только dev/staging)
make psqlpsql внутри контейнера
make testgo test ./... unit-тесты
make test-integrationgo test -tags=integration ./...
make lintgolangci-lint run
make fmtgofmt + goimports

В handbook-репо (этот): make serve, make build, make check — см. ../Makefile.

Запрещённые практики (частое)

Частый checklist на PR-review:

  • Не использовать fmt.Sprintf с user input в SQL — только плейсхолдеры $1.
  • Не логировать Authorization header, email в открытом виде.
  • Не делать cross-database JOIN между сервисами (у каждого — своя БД).
  • Не вызывать Kafka/HTTP внутри InTx — только БД-операции.
  • Не хардкодить секреты и DSN в коде.
  • Не делать offset-пагинацию на публичных list-endpoint’ах.
  • Не оборачивать pgx в ORM.
  • Не ставить InsecureSkipVerify: true в HTTP-клиенте.
  • Не держать in-memory cache без bounded размера.
  • Не go func() { ... }() без отмены по ctx.
  • Не context.Background() в handler’е.
  • Не time.Tick в long-running worker’е — только NewTicker + Stop().
  • Не map[string]any вместо типизированного struct’а.

Связанные разделы

  • conventions/ — полные правила по темам.
  • patterns/ — deep-dive по архитектурным паттернам.
  • how-to/ — пошаговые рецепты.
  • troubleshooting/ — runbook’и.
  • glossary — расшифровка терминов.
Last updated on