// Package di provides dependency injection container and providers using uber-go/fx. package di import ( "context" "os" "os/signal" "syscall" "time" "go.uber.org/fx" ) // Container wraps the FX application and provides lifecycle management. type Container struct { app *fx.App } // NewContainer creates a new DI container with the provided options. func NewContainer(opts ...fx.Option) *Container { // Add core module allOpts := []fx.Option{CoreModule()} allOpts = append(allOpts, opts...) app := fx.New(allOpts...) return &Container{ app: app, } } // Start starts the container and blocks until shutdown. func (c *Container) Start(ctx context.Context) error { // Start the FX app if err := c.app.Start(ctx); err != nil { return err } // Wait for interrupt signal sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM) // Block until signal received <-sigChan // Create shutdown context shutdownCtx, cancel := context.WithTimeout(context.Background(), c.getShutdownTimeout()) defer cancel() // Stop the FX app if err := c.app.Stop(shutdownCtx); err != nil { return err } return nil } // Stop stops the container gracefully. func (c *Container) Stop(ctx context.Context) error { return c.app.Stop(ctx) } // getShutdownTimeout returns the shutdown timeout duration. // Can be made configurable in the future. func (c *Container) getShutdownTimeout() time.Duration { return 30 * time.Second }