Infra
Toolkit · pkg/infra/
Инфраструктурные примитивы которые обслуживают сам проект. Инициализируются первыми — раньше services и apps.
pkg/infra/
├── main.go — Configs + Init + Stop (только если нужно)
├── logs/ — глобальный логгер
├── tracer/ — distributed tracing
├── eventbus/ — внутренний publish/subscribe
└── vars/ — env-переменные и feature flagsЧто такое infra
Обёртки над системами которые обслуживают сам проект — логирование, трассировка, внутренний event bus. В отличие от pkg/services, которые использует бизнес-логика, pkg/infra нужна всем слоям независимо от того что делает приложение.
Infra не обязана следовать паттерну сервиса. Примитив может не иметь Configs, Init, Stop и интерфейса — достаточно набора глобальных функций. Форма определяется потребностью конкретного примитива.
main.go появляется только когда есть что инициализировать. Если все примитивы самодостаточны — он не нужен.
logs
Глобальный логгер. Простейший случай — набор функций без состояния после Init.
package logs
func Init(configs Configs) { ... }
func Infof(format string, args ...interface{}) { ... }
func Errorf(format string, args ...interface{}) { ... }
func Warnf(format string, args ...interface{}) { ... }
func Fatalf(format string, args ...interface{}) { ... }
func InfoWithFields(obj interface{}, message string) { ... }
func ErrorWithFields(obj interface{}, message string) { ... }Все слои импортируют pkg/infra/logs, а не конкретную библиотеку напрямую. Это позволяет поменять реализацию в одном месте.
vars
Env-переменные и настройки которые не принадлежат ни одному конкретному сервису — имя окружения, feature flags, shared-значения.
package vars
type Configs struct {
Env string `json:"env"`
FeatureFlags map[string]bool `json:"feature_flags"`
}
var cfg Configs
func Init(configs Configs){
cfg = configs
}
func Get() {return cfg}Использование:
if vars.Get().Env == "dev" { ... }tracer
Distributed tracing — трассировка запроса через все слои. Конкретная реализация (OpenTelemetry, Jaeger и др.) скрыта за функциями пакета.
eventbus
Внутренний publish/subscribe для event-driven логики в монолите. Любой слой публикует событие без прямой зависимости от обработчика.
package eventbus
func Publish(id string, payload any) { ... }
func Register(events []Event) { ... }
type Event struct {
ID string
Handler func(payload any) error
Mode EventMode
}
type EventMode int
const (
Instant EventMode = iota // горутина, fire and forget
WorkerPool // канал + N воркеров, контроль нагрузки
Queue // буферизованный канал, гарантия порядка
)Обработчики описываются в internal/delivery/events/ и регистрируются через event_bus_app — отдельный App в cmd/apps, который при Init вызывает eventbus.Register, а при Exec слушает и диспетчеризует события.
В микросервисах eventbus не нужен — event-driven выносится на уровень инфраструктуры (Pub/Sub, Kafka).
Правила
- Infra инициализируется первой. Логгер нужен всем уже при старте остальных слоёв.
- Доступ через функции пакета, не через геттеры как в services:
logs.Infof(...), неinfra.Logs().Infof(...). - Форма свободная. Не нужно натягивать паттерн сервиса если примитив в нём не нуждается.
- Нет привязки к предметной области. Если примитив знает о конкретных сущностях проекта — он не infra.