Files
2026-04-13 08:14:09 +03:00

116 lines
3.5 KiB
Go

package main
// Пример циклической зависимости в Fx.
//
// Граф зависимостей замкнулся в кольцо:
//
// NewEventBus(NotificationSender) — EventBus хочет отправлять уведомления
// NewNotificationService(Users, EventSubscriber) — уведомления хотят знать email
// NewUserService(Auth) — пользователи хотят проверять токен
// NewAuthService(EventPublisher) — авторизация хочет публиковать события
// ↑ ↓
// └──────── EventBus реализует EventPublisher ─────────┘
//
// Ни один объект нельзя создать первым — каждому нужен ещё не созданный.
//
// Wire ловит такой цикл при кодогенерации (до запуска).
// Fx ловит его в рантайме (при старте приложения).
// Результат одинаковый — приложение не запустится.
//
// Запустите: go run ./cmd/fx-di-broken/
// Результат: ошибка "In: cannot depend on the provided type"
import (
"log/slog"
"go.uber.org/fx"
)
// === Интерфейсы ===
type NotificationSender interface {
Send(msg string)
}
type EventPublisher interface {
Publish(event string)
}
type EventSubscriber interface {
Subscribe(event string, handler func())
}
type Auth interface {
Validate(token string) bool
}
type Users interface {
GetEmail(userID int) string
}
// === Реализации ===
type EventBus struct {
notifications NotificationSender // ← вот она, циклическая зависимость
}
func NewEventBus(notifications NotificationSender) *EventBus {
slog.Info("шина событий создана")
return &EventBus{notifications: notifications}
}
func (b *EventBus) Publish(event string) {}
func (b *EventBus) Subscribe(event string, handler func()) {}
type AuthService struct {
events EventPublisher
}
func NewAuthService(events EventPublisher) *AuthService {
slog.Info("сервис авторизации создан")
return &AuthService{events: events}
}
func (s *AuthService) Validate(token string) bool { return true }
type UserService struct {
auth Auth
}
func NewUserService(auth Auth) *UserService {
slog.Info("сервис пользователей создан")
return &UserService{auth: auth}
}
func (s *UserService) GetEmail(userID int) string { return "user@example.com" }
type NotificationService struct {
users Users
events EventSubscriber
}
func NewNotificationService(users Users, events EventSubscriber) *NotificationService {
slog.Info("сервис уведомлений создан")
return &NotificationService{users: users, events: events}
}
func (s *NotificationService) Send(msg string) {
slog.Info("уведомление отправлено", "msg", msg)
}
// === Fx ===
func main() {
fx.New(
fx.Provide(
fx.Annotate(NewEventBus, fx.As(new(EventPublisher)), fx.As(new(EventSubscriber))),
fx.Annotate(NewAuthService, fx.As(new(Auth))),
fx.Annotate(NewUserService, fx.As(new(Users))),
fx.Annotate(NewNotificationService, fx.As(new(NotificationSender))),
),
fx.Invoke(func(pub EventPublisher) {
slog.Info("всё запустилось") // сюда не дойдём
}),
).Run()
}