Quick reference¶
Одностраничная шпаргалка: именные соглашения, стандартные env-переменные,
статусы HTTP → sentinel, Kafka topic naming, типовые метрики. Это не
первоисточник — за деталями ходи в соответствующие conventions/. Эта
страница — для «быстро напомнить формат».
Содержание¶
- HTTP status → sentinel → code
- Kafka: topic naming
- Kafka: envelope metadata
- Consumer-group naming
- Метрики: naming и suffix'ы
- Env-переменные: префиксы и дефолты
- pgx: частые паттерны
- Файловая раскладка сервиса
- Логирование: обязательные поля
- Таймауты
- Correlation IDs
- Makefile targets
- Запрещённые практики (частое)
- Связанные разделы
HTTP status → sentinel → code¶
Полный маппинг — в conventions/http-api.md.
| Service sentinel | HTTP | Response code |
|---|---|---|
service.ErrNotFound |
404 | not_found |
service.ErrValidation |
400 | invalid_input |
service.ErrUnauthorized |
401 | unauthorized |
service.ErrForbidden |
403 | forbidden |
service.ErrConflict |
409 | conflict |
service.ErrRateLimit |
429 | rate_limited |
| default (unknown) | 500 | internal |
Правила:
- Никаких
http.StatusXпрямо в handler'е — только черезmapServiceError. - 4xx — клиент виноват, retry не поможет (кроме 429).
- 5xx — сервис виноват, retry имеет смысл (см.
patterns/retry-and-circuit-breaker.md).
Kafka: topic naming¶
Формат: kazmaps.<service>.<entity>.<action>.
kazmaps.user.user.registered
kazmaps.user.user.banned
kazmaps.review.review.created
kazmaps.review.review.updated
kazmaps.review.review.deleted
kazmaps.media.photo.uploaded
kazmaps.media.moderation.approved
<service>— publisher-сервис (owner).<entity>— существительное, единственное число.<action>— прошедшее время (факт уже произошёл):created,updated,deleted,completed,failed,approved,banned.- DLQ:
<topic>.dlq. Примеры:kazmaps.review.review.created.dlq.
Подробно — conventions/events.md.
Kafka: envelope metadata¶
Обязательные поля в Message.Metadata:
| Поле | Пример |
|---|---|
Event-Type |
review.created |
Schema-Version |
"1" |
Correlation-Id |
ULID |
Source-Service |
review |
Published-At |
RFC3339Nano |
traceparent |
W3C 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 начинает с
latestoffset'а (см. config). Думай заранее.
Метрики: naming и suffix'ы¶
Формат: <domain>_<action>_<unit>, snake_case.
| Suffix | Тип | Пример |
|---|---|---|
_seconds |
Histogram | kafka_publish_duration_seconds |
_bytes |
Histogram | media_upload_bytes |
_total |
Counter | user_registrations_total |
_ratio |
Gauge (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.md.
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.md.
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.md.
Файловая раскладка сервиса¶
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.md.
Логирование: обязательные поля¶
В каждой строке лога:
| Поле | Значение |
|---|---|
service |
"review" |
level |
info, warn, error (не debug в prod) |
time |
RFC3339Nano |
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.md.
Таймауты¶
Типовые значения:
| Компонент | Timeout |
|---|---|
HTTP server ReadHeaderTimeout |
10s |
HTTP server ReadTimeout |
30s |
HTTP server WriteTimeout |
60s |
HTTP server IdleTimeout |
120s |
chi Timeout middleware |
30s |
Outbound HTTP-client Timeout |
5–10s |
Postgres statement_timeout |
30s (через env) |
| Redis op timeout | 1s |
Kafka producer Timeout |
10s |
Kafka consumer session.timeout.ms |
45–60s |
Kafka consumer max.poll.interval.ms |
300s (не маскировать медленный handler) |
Всегда есть ctx.Done() — handler обязан уважать.
Correlation IDs¶
Три ID, связывающие сигналы в один запрос:
| ID | Header | Где ещё |
|---|---|---|
request_id |
X-Request-Id |
ставит chimw.RequestID, per-request |
correlation_id |
X-Correlation-Id |
ULID, переживает цепочку HTTP→Kafka→HTTP |
trace_id |
traceparent (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 up |
docker compose up -d |
make down |
docker compose down (volumes сохраняются) |
make clean |
docker compose down -v (чистый старт) |
make rebuild |
docker compose build && up -d |
make logs |
docker compose logs -f <service> |
make migrate-up |
migrate up |
make migrate-down |
migrate down 1 (только dev/staging) |
make psql |
psql внутри контейнера |
make test |
go test ./... unit-тесты |
make test-integration |
go test -tags=integration ./... |
make lint |
golangci-lint run |
make fmt |
gofmt + goimports |
В handbook-репо (этот): make serve, make build, make check —
см. ../Makefile.
Запрещённые практики (частое)¶
Частый checklist на PR-review:
- Не использовать
fmt.Sprintfс user input в SQL — только плейсхолдеры$1. - Не логировать Authorization header, email в открытом виде.
- Не делать cross-schema
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.md— расшифровка терминов.