//go:build wireinject // +build wireinject package main import ( "context" "log" "net/http" "time" "github.com/Wei-Shaw/sub2api/internal/config" "github.com/Wei-Shaw/sub2api/internal/handler" "github.com/Wei-Shaw/sub2api/internal/infrastructure" "github.com/Wei-Shaw/sub2api/internal/repository" "github.com/Wei-Shaw/sub2api/internal/server" "github.com/Wei-Shaw/sub2api/internal/server/middleware" "github.com/Wei-Shaw/sub2api/internal/service" "github.com/google/wire" "github.com/redis/go-redis/v9" "gorm.io/gorm" ) type Application struct { Server *http.Server Cleanup func() } func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) { wire.Build( // Infrastructure layer ProviderSets config.ProviderSet, infrastructure.ProviderSet, // Business layer ProviderSets repository.ProviderSet, service.ProviderSet, middleware.ProviderSet, handler.ProviderSet, // Server layer ProviderSet server.ProviderSet, // BuildInfo provider provideServiceBuildInfo, // Cleanup function provider provideCleanup, // Application struct wire.Struct(new(Application), "Server", "Cleanup"), ) return nil, nil } func provideServiceBuildInfo(buildInfo handler.BuildInfo) service.BuildInfo { return service.BuildInfo{ Version: buildInfo.Version, BuildType: buildInfo.BuildType, } } func provideCleanup( db *gorm.DB, rdb *redis.Client, tokenRefresh *service.TokenRefreshService, pricing *service.PricingService, emailQueue *service.EmailQueueService, oauth *service.OAuthService, openaiOAuth *service.OpenAIOAuthService, geminiOAuth *service.GeminiOAuthService, antigravityOAuth *service.AntigravityOAuthService, antigravityQuota *service.AntigravityQuotaRefresher, ) func() { return func() { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() // Cleanup steps in reverse dependency order cleanupSteps := []struct { name string fn func() error }{ {"TokenRefreshService", func() error { tokenRefresh.Stop() return nil }}, {"PricingService", func() error { pricing.Stop() return nil }}, {"EmailQueueService", func() error { emailQueue.Stop() return nil }}, {"OAuthService", func() error { oauth.Stop() return nil }}, {"OpenAIOAuthService", func() error { openaiOAuth.Stop() return nil }}, {"GeminiOAuthService", func() error { geminiOAuth.Stop() return nil }}, {"AntigravityOAuthService", func() error { antigravityOAuth.Stop() return nil }}, {"AntigravityQuotaRefresher", func() error { antigravityQuota.Stop() return nil }}, {"Redis", func() error { return rdb.Close() }}, {"Database", func() error { sqlDB, err := db.DB() if err != nil { return err } return sqlDB.Close() }}, } for _, step := range cleanupSteps { if err := step.fn(); err != nil { log.Printf("[Cleanup] %s failed: %v", step.name, err) // Continue with remaining cleanup steps even if one fails } else { log.Printf("[Cleanup] %s succeeded", step.name) } } // Check if context timed out select { case <-ctx.Done(): log.Printf("[Cleanup] Warning: cleanup timed out after 10 seconds") default: log.Printf("[Cleanup] All cleanup steps completed") } } }