fix: ensure database and HTTP server providers execute on startup

- Add fx.Invoke in main.go to force database and HTTP server creation
- This ensures all providers execute and their lifecycle hooks are registered
- Clean up debug logging statements
- Database migrations and HTTP server now start correctly on application startup

Fixes issue where database migrations and HTTP server were not starting
because FX providers were not being executed (lazy evaluation).
This commit is contained in:
2025-11-05 20:32:20 +01:00
parent 84673c33b1
commit 0e3bfb4e44
3 changed files with 31 additions and 4 deletions

View File

@@ -7,15 +7,24 @@ import (
"os" "os"
"git.dcentral.systems/toolz/goplt/internal/di" "git.dcentral.systems/toolz/goplt/internal/di"
"git.dcentral.systems/toolz/goplt/internal/infra/database"
"git.dcentral.systems/toolz/goplt/internal/server"
"git.dcentral.systems/toolz/goplt/pkg/logger" "git.dcentral.systems/toolz/goplt/pkg/logger"
"go.uber.org/fx" "go.uber.org/fx"
) )
func main() { func main() {
// Create DI container with lifecycle hooks // Create DI container with lifecycle hooks
// We need to invoke the HTTP server to ensure all providers execute
container := di.NewContainer( container := di.NewContainer(
// Invoke lifecycle hooks // Invoke lifecycle hooks
fx.Invoke(di.RegisterLifecycleHooks), fx.Invoke(di.RegisterLifecycleHooks),
// Force HTTP server to be created (which triggers all dependencies)
// This ensures database, health, metrics, etc. are all created
fx.Invoke(func(srv *server.Server, dbClient *database.Client) {
// Both server and database are created, hooks are registered
// This ensures all providers execute
}),
) )
// Create root context // Create root context

View File

@@ -1,7 +1,7 @@
environment: development environment: development
server: server:
port: 8080 port: 3000
host: "0.0.0.0" host: "0.0.0.0"
read_timeout: 30s read_timeout: 30s
write_timeout: 30s write_timeout: 30s

View File

@@ -70,6 +70,7 @@ func ProvideDatabase() fx.Option {
return fx.Provide(func(cfg config.ConfigProvider, log logger.Logger, lc fx.Lifecycle) (*database.Client, error) { return fx.Provide(func(cfg config.ConfigProvider, log logger.Logger, lc fx.Lifecycle) (*database.Client, error) {
dsn := cfg.GetString("database.dsn") dsn := cfg.GetString("database.dsn")
if dsn == "" { if dsn == "" {
log.Error("ProvideDatabase: DSN is empty")
return nil, fmt.Errorf("database DSN is not configured") return nil, fmt.Errorf("database DSN is not configured")
} }
@@ -93,6 +94,12 @@ func ProvideDatabase() fx.Option {
connMaxIdleTime = 10 * time.Minute connMaxIdleTime = 10 * time.Minute
} }
log.Info("Preparing database connection",
logger.String("dsn_mask", maskDSN(dsn)),
logger.Int("max_connections", maxConns),
)
log.Info("Connecting to database...")
dbClient, err := database.NewClient(database.Config{ dbClient, err := database.NewClient(database.Config{
DSN: dsn, DSN: dsn,
MaxConnections: maxConns, MaxConnections: maxConns,
@@ -101,14 +108,19 @@ func ProvideDatabase() fx.Option {
ConnMaxIdleTime: connMaxIdleTime, ConnMaxIdleTime: connMaxIdleTime,
}) })
if err != nil { if err != nil {
log.Error("Failed to create database client",
logger.Error(err),
)
return nil, fmt.Errorf("failed to create database client: %w", err) return nil, fmt.Errorf("failed to create database client: %w", err)
} }
log.Info("Database client created successfully")
// Register lifecycle hooks // Register lifecycle hooks
lc.Append(fx.Hook{ lc.Append(fx.Hook{
OnStart: func(ctx context.Context) error { OnStart: func(ctx context.Context) error {
// Run migrations on startup
log.Info("Running database migrations...") log.Info("Running database migrations...")
// Run migrations on startup
if err := dbClient.Migrate(ctx); err != nil { if err := dbClient.Migrate(ctx); err != nil {
log.Error("Database migrations failed", log.Error("Database migrations failed",
logger.Error(err), logger.Error(err),
@@ -222,16 +234,22 @@ func ProvideHTTPServer() fx.Option {
tracer trace.TracerProvider, tracer trace.TracerProvider,
lc fx.Lifecycle, lc fx.Lifecycle,
) (*server.Server, error) { ) (*server.Server, error) {
log.Info("Creating HTTP server...")
srv, err := server.NewServer(cfg, log, healthRegistry, metricsRegistry, errorBus, tracer) srv, err := server.NewServer(cfg, log, healthRegistry, metricsRegistry, errorBus, tracer)
if err != nil { if err != nil {
log.Error("Failed to create HTTP server",
logger.Error(err),
)
return nil, fmt.Errorf("failed to create HTTP server: %w", err) return nil, fmt.Errorf("failed to create HTTP server: %w", err)
} }
log.Info("HTTP server created, registering lifecycle hooks...")
// Register lifecycle hooks // Register lifecycle hooks
lc.Append(fx.Hook{ lc.Append(fx.Hook{
OnStart: func(ctx context.Context) error { OnStart: func(ctx context.Context) error {
log.Info("HTTP server OnStart hook called")
// Get server address from config // Get server address from config
port := cfg.GetInt("server.port") port := cfg.GetInt("server.port")
if port == 0 { if port == 0 {