From 4c2ab23fab812f0399f0f695a884960c48ac89ca Mon Sep 17 00:00:00 2001 From: Primadi Setiawan Date: Mon, 1 Dec 2025 16:21:11 +0700 Subject: [PATCH] fix bug autocreate dbpool-manager --- bootstrap.go | 35 ++++- .../01_enterprise_router_service/main.go | 4 +- .../examples/01-basic-config/README.md | 4 +- .../examples/01-basic-config/main.go | 4 +- .../04-config/examples/06-handlers/main.go | 4 +- docs/BOOTSTRAP-FLOWS.md | 32 ++--- docs/BOOTSTRAP-QUICK-GUIDE.txt | 133 ------------------ docs/CONFIG-FIRST-IMPLEMENTATION.md | 9 +- lokstra_registry/deployment.go | 5 - lokstra_registry/helper.go | 22 ++- .../README_FLOWS.md | 4 +- .../03_enterprise_router_service/main.go | 5 +- .../example/example_multi_db.go | 5 +- 13 files changed, 70 insertions(+), 196 deletions(-) delete mode 100644 docs/BOOTSTRAP-QUICK-GUIDE.txt diff --git a/bootstrap.go b/bootstrap.go index 785c0e09..8b44fcc8 100644 --- a/bootstrap.go +++ b/bootstrap.go @@ -70,6 +70,8 @@ func Bootstrap(scanPath ...string) { os.Exit(0) } + autoCreateDbPoolManager() + // 2️⃣ Detect mode and store in config for runtime access Mode = detectRunMode() lokstra_registry.SetConfig("runtime.mode", string(Mode)) @@ -81,12 +83,6 @@ func Bootstrap(scanPath ...string) { return } - // auto create dbpool-manager service if not exists - if svc := lokstra_registry.GetService[serviceapi.DbPoolManager]("dbpool-manager"); svc == nil { - svc = dbpool_manager.NewPgxPoolManager() - lokstra_registry.RegisterService("dbpool-manager", svc) - } - // 4️⃣ If prod, just continue if Mode == RunModeProd { // fmt.Println("[Lokstra] Production mode — skipping autogen.") @@ -285,3 +281,30 @@ func relaunchWithDlv() { // Exit cleanly so debugger can be restarted os.Exit(0) } + +// auto create dbpool-manager service if not exists +func autoCreateDbPoolManager() { + if svc := lokstra_registry.GetService[serviceapi.DbPoolManager]("dbpool-manager"); svc == nil { + svc = dbpool_manager.NewPgxPoolManager() + lokstra_registry.RegisterService("dbpool-manager", svc) + } +} + +// LoadConfigFromFolder loads configuration from the specified folder path. +// It also ensures that the dbpool-manager service is registered before loading config. +func LoadConfigFromFolder(folderPath string) error { + autoCreateDbPoolManager() + return lokstra_registry.LoadConfigFromFolder(folderPath) +} + +// LoadConfig loads configuration from the specified file path. +// It also ensures that the dbpool-manager service is registered before loading config. +func LoadConfig(filePath string) error { + autoCreateDbPoolManager() + return lokstra_registry.LoadConfig(filePath) +} + +// InitAndRunServer initializes and runs the server based on loaded configuration. +func InitAndRunServer() error { + return lokstra_registry.InitAndRunServer() +} diff --git a/docs/00-introduction/examples/full-framework/01_enterprise_router_service/main.go b/docs/00-introduction/examples/full-framework/01_enterprise_router_service/main.go index 633b8aff..75d40482 100644 --- a/docs/00-introduction/examples/full-framework/01_enterprise_router_service/main.go +++ b/docs/00-introduction/examples/full-framework/01_enterprise_router_service/main.go @@ -20,7 +20,7 @@ func main() { deploy.SetLogLevelFromEnv() - lokstra_registry.LoadConfigFromFolder("config") + lokstra.LoadConfigFromFolder("config") dsn := lokstra_registry.GetConfig("global-db.dsn", "") schema := lokstra_registry.GetConfig("global-db.schema", "public") @@ -44,7 +44,7 @@ func main() { registerMiddlewareTypes() // 3. Run server from config folder - if err := lokstra_registry.InitAndRunServer(); err != nil { + if err := lokstra.InitAndRunServer(); err != nil { panic(err) } } diff --git a/docs/02-framework-guide/04-config/examples/01-basic-config/README.md b/docs/02-framework-guide/04-config/examples/01-basic-config/README.md index 88e59a2f..564da859 100644 --- a/docs/02-framework-guide/04-config/examples/01-basic-config/README.md +++ b/docs/02-framework-guide/04-config/examples/01-basic-config/README.md @@ -89,7 +89,7 @@ func main() { lokstra.Bootstrap() // STEP 2: Load Config - loads YAML configuration - lokstra_registry.LoadConfig("config.yaml") + lokstra.LoadConfig("config.yaml") // STEP 3: Register Service Types - map factory names to functions registerServiceTypes() @@ -98,7 +98,7 @@ func main() { registerMiddlewareTypes() // STEP 5: Initialize and Run Server - lokstra_registry.InitAndRunServer() + lokstra.InitAndRunServer() } ``` diff --git a/docs/02-framework-guide/04-config/examples/01-basic-config/main.go b/docs/02-framework-guide/04-config/examples/01-basic-config/main.go index 87ab4385..0ea87ccc 100644 --- a/docs/02-framework-guide/04-config/examples/01-basic-config/main.go +++ b/docs/02-framework-guide/04-config/examples/01-basic-config/main.go @@ -13,7 +13,7 @@ func main() { lokstra.Bootstrap() // STEP 1: Load Config - if err := lokstra_registry.LoadConfig("config.yaml"); err != nil { + if err := lokstra.LoadConfig("config.yaml"); err != nil { log.Fatal("Failed to load config:", err) } @@ -24,7 +24,7 @@ func main() { registerMiddlewareTypes() // STEP 4: Initialize and Run Server - if err := lokstra_registry.InitAndRunServer(); err != nil { + if err := lokstra.InitAndRunServer(); err != nil { log.Fatal("Failed to run server:", err) } } diff --git a/docs/02-framework-guide/04-config/examples/06-handlers/main.go b/docs/02-framework-guide/04-config/examples/06-handlers/main.go index 38d9e05f..91d1aac4 100644 --- a/docs/02-framework-guide/04-config/examples/06-handlers/main.go +++ b/docs/02-framework-guide/04-config/examples/06-handlers/main.go @@ -12,7 +12,7 @@ func main() { lokstra.Bootstrap() // STEP 1: Load Config - if err := lokstra_registry.LoadConfig("config.yaml"); err != nil { + if err := lokstra.LoadConfig("config.yaml"); err != nil { log.Fatal("Failed to load config:", err) } @@ -23,7 +23,7 @@ func main() { registerMiddlewareTypes() // STEP 4: Initialize and Run Server - if err := lokstra_registry.InitAndRunServer(); err != nil { + if err := lokstra.InitAndRunServer(); err != nil { log.Fatal("Failed to run server:", err) } } diff --git a/docs/BOOTSTRAP-FLOWS.md b/docs/BOOTSTRAP-FLOWS.md index 48f7a937..82824538 100644 --- a/docs/BOOTSTRAP-FLOWS.md +++ b/docs/BOOTSTRAP-FLOWS.md @@ -102,7 +102,6 @@ import ( "log" "github.com/primadi/lokstra" "github.com/primadi/lokstra/core/deploy" - "github.com/primadi/lokstra/lokstra_registry" ) func main() { @@ -110,7 +109,7 @@ func main() { deploy.SetLogLevelFromEnv() // 1. Load config FIRST - if err := lokstra_registry.LoadConfigFromFolder("config"); err != nil { + if err := lokstra.LoadConfigFromFolder("config"); err != nil { log.Fatal("Failed to load config:", err) } @@ -121,7 +120,7 @@ func main() { registerMiddlewareTypes() // 4. Initialize and run server - if err := lokstra_registry.InitAndRunServer(); err != nil { + if err := lokstra.InitAndRunServer(); err != nil { log.Fatal("Failed to run server:", err) } } @@ -173,7 +172,7 @@ func main() { deploy.SetLogLevelFromEnv() // Load config first - if err := lokstra_registry.LoadConfigFromFolder("config"); err != nil { + if err := lokstra.LoadConfigFromFolder("config"); err != nil { log.Fatal("Failed to load config:", err) } @@ -182,7 +181,7 @@ func main() { registerMiddlewareTypes() // Start server - if err := lokstra_registry.InitAndRunServer(); err != nil { + if err := lokstra.InitAndRunServer(); err != nil { log.Fatal("Failed to run server:", err) } } @@ -241,20 +240,19 @@ package main import ( "log" "github.com/primadi/lokstra" - "github.com/primadi/lokstra/lokstra_registry" ) func main() { lokstra.Bootstrap() // Load single config file - if err := lokstra_registry.LoadConfig("config.yaml"); err != nil { + if err := lokstra.LoadConfig("config.yaml"); err != nil { log.Fatal(err) } registerServiceTypes() - if err := lokstra_registry.InitAndRunServer(); err != nil { + if err := lokstra.InitAndRunServer(); err != nil { log.Fatal(err) } } @@ -268,14 +266,13 @@ package main import ( "log" "github.com/primadi/lokstra" - "github.com/primadi/lokstra/lokstra_registry" ) func main() { lokstra.Bootstrap() // Load multiple config files - if err := lokstra_registry.LoadConfig( + if err := lokstra.LoadConfig( "config/base.yaml", "config/services.yaml", "config/deployments.yaml", @@ -286,7 +283,7 @@ func main() { registerServiceTypes() registerMiddlewareTypes() - if err := lokstra_registry.InitAndRunServer(); err != nil { + if err := lokstra.InitAndRunServer(); err != nil { log.Fatal(err) } } @@ -300,21 +297,20 @@ package main import ( "log" "github.com/primadi/lokstra" - "github.com/primadi/lokstra/lokstra_registry" ) func main() { lokstra.Bootstrap() // Load all YAML files from folder - if err := lokstra_registry.LoadConfigFromFolder("config"); err != nil { + if err := lokstra.LoadConfigFromFolder("config"); err != nil { log.Fatal(err) } registerServiceTypes() registerMiddlewareTypes() - if err := lokstra_registry.InitAndRunServer(); err != nil { + if err := lokstra.InitAndRunServer(); err != nil { log.Fatal(err) } } @@ -359,10 +355,10 @@ Loads YAML configuration file(s) and registers lazy load services. ```go // Single file -err := lokstra_registry.LoadConfig("config.yaml") +err := lokstra.LoadConfig("config.yaml") // Multiple files -err := lokstra_registry.LoadConfig( +err := lokstra.LoadConfig( "config/base.yaml", "config/services.yaml", ) @@ -373,7 +369,7 @@ err := lokstra_registry.LoadConfig( Loads all YAML files from the specified folder. ```go -err := lokstra_registry.LoadConfigFromFolder("config") +err := lokstra.LoadConfigFromFolder("config") ``` #### `InitAndRunServer() error` @@ -385,7 +381,7 @@ Initializes and runs the server based on loaded config. // - server: Server selection (optional, uses first if not specified) // - shutdown_timeout: Graceful shutdown timeout (optional, default: 30s) -err := lokstra_registry.InitAndRunServer() +err := lokstra.InitAndRunServer() ``` #### `GetConfig[T any](key string, defaultValue T) T` diff --git a/docs/BOOTSTRAP-QUICK-GUIDE.txt b/docs/BOOTSTRAP-QUICK-GUIDE.txt deleted file mode 100644 index 2dee8e17..00000000 --- a/docs/BOOTSTRAP-QUICK-GUIDE.txt +++ /dev/null @@ -1,133 +0,0 @@ -┌─────────────────────────────────────────────────────────────────────┐ -│ LOKSTRA BOOTSTRAP QUICK GUIDE │ -└─────────────────────────────────────────────────────────────────────┘ - -┌─────────────────────────────────────────────────────────────────────┐ -│ NEW FLOW (RECOMMENDED) - Config First │ -└─────────────────────────────────────────────────────────────────────┘ - -┌──────────────────┐ -│ 1. Load Config │ Config is loaded and available -└──────────────────┘ - - if err := lokstra_registry.LoadConfigFromFolder("config"); err != nil { - log.Fatal(err) - } - -┌──────────────────────┐ -│ 2. Register Services │ ✅ Config is available here! -└──────────────────────┘ - - registerServiceTypes() - registerMiddlewareTypes() - -┌────────────────┐ -│ 3. Run Server │ Just starts the server -└────────────────┘ - - if err := lokstra_registry.InitAndRunServer(); err != nil { - log.Fatal(err) - } - - -┌─────────────────────────────────────────────────────────────────────┐ -│ Service Factory - Access Global Config │ -└─────────────────────────────────────────────────────────────────────┘ - -func UserServiceFactory(deps map[string]any, config map[string]any) any { - // Access global config from YAML - dbDSN := lokstra_registry.GetConfig("database.dsn", "postgres://...") - cacheEnabled := lokstra_registry.GetConfig("cache.enabled", true) - cacheTTL := lokstra_registry.GetConfig("cache.ttl", 300) - - return &UserServiceImpl{ - UserRepo: service.Cast[UserRepository](deps["user-repository"]), - CacheEnabled: cacheEnabled, - CacheTTL: time.Duration(cacheTTL) * time.Second, - } -} - - -┌─────────────────────────────────────────────────────────────────────┐ -│ Config YAML - Global Configs Section │ -└─────────────────────────────────────────────────────────────────────┘ - -# New: Global configs (accessible in service factories) -configs: - database: - dsn: "postgres://localhost:5432/mydb" - cache: - enabled: true - ttl: 300 - -service-definitions: - user-service: - type: user-service-factory - depends-on: [user-repository] - - -┌─────────────────────────────────────────────────────────────────────┐ -│ OLD FLOW (Still Supported) │ -└─────────────────────────────────────────────────────────────────────┘ - -func main() { - lokstra.Bootstrap() - - registerServiceTypes() // ❌ Config not available - registerMiddlewareTypes() // ❌ Config not available - - // Config loaded + server started together - lokstra_registry.RunServerFromConfigFolder("config") -} - - -┌─────────────────────────────────────────────────────────────────────┐ -│ API Functions │ -└─────────────────────────────────────────────────────────────────────┘ - -LoadConfig(paths ...string) error - Load specific YAML file(s) - -LoadConfigFromFolder(folder string) error - Load all YAML files from folder - -InitAndRunServer() error - Start server from loaded config - -GetConfig[T](key string, default T) T - Retrieve config value with type safety - - -┌─────────────────────────────────────────────────────────────────────┐ -│ Benefits of New Flow │ -└─────────────────────────────────────────────────────────────────────┘ - -✅ Config available during service registration -✅ Early config validation (errors detected sooner) -✅ Service factories can read global config -✅ More intuitive and easier to debug -✅ Better separation of concerns - - -┌─────────────────────────────────────────────────────────────────────┐ -│ Migration Steps │ -└─────────────────────────────────────────────────────────────────────┘ - -1. Replace RunServerFromConfigFolder() with: - - LoadConfigFromFolder("config") - // ... register services ... - InitAndRunServer() - -2. (Optional) Update service factories to use GetConfig() - -3. (Optional) Add global configs section to YAML - - -┌─────────────────────────────────────────────────────────────────────┐ -│ See Also │ -└─────────────────────────────────────────────────────────────────────┘ - -📚 docs/BOOTSTRAP-FLOWS.md - Complete documentation -📚 docs/CONFIG-FIRST-IMPLEMENTATION.md - Implementation details -🔧 project_templates/.../main_new_flow.go - Example code diff --git a/docs/CONFIG-FIRST-IMPLEMENTATION.md b/docs/CONFIG-FIRST-IMPLEMENTATION.md index e59dbc51..aff5a630 100644 --- a/docs/CONFIG-FIRST-IMPLEMENTATION.md +++ b/docs/CONFIG-FIRST-IMPLEMENTATION.md @@ -80,7 +80,6 @@ import ( "log" "github.com/primadi/lokstra" "github.com/primadi/lokstra/core/deploy" - "github.com/primadi/lokstra/lokstra_registry" ) func main() { @@ -88,7 +87,7 @@ func main() { deploy.SetLogLevelFromEnv() // 1. Load config FIRST - if err := lokstra_registry.LoadConfigFromFolder("config"); err != nil { + if err := lokstra.LoadConfigFromFolder("config"); err != nil { log.Fatal("Failed to load config:", err) } @@ -99,7 +98,7 @@ func main() { registerMiddlewareTypes() // 4. Initialize and run server - if err := lokstra_registry.InitAndRunServer(); err != nil { + if err := lokstra.InitAndRunServer(); err != nil { log.Fatal("Failed to run server:", err) } } @@ -180,11 +179,11 @@ Replace `RunServerFromConfigFolder()` with 3 separate calls: lokstra_registry.RunServerFromConfigFolder("config") // After -if err := lokstra_registry.LoadConfigFromFolder("config"); err != nil { +if err := lokstra.LoadConfigFromFolder("config"); err != nil { log.Fatal(err) } // ... register services/middlewares ... -if err := lokstra_registry.InitAndRunServer(); err != nil { +if err := lokstra.InitAndRunServer(); err != nil { log.Fatal(err) } ``` diff --git a/lokstra_registry/deployment.go b/lokstra_registry/deployment.go index 7c6abec3..b9c32daf 100644 --- a/lokstra_registry/deployment.go +++ b/lokstra_registry/deployment.go @@ -28,11 +28,6 @@ func getFirstServerCompositeKey() string { return registry.GetFirstServerCompositeKey() } -// LoadAndBuild loads config and builds ALL deployments into Global registry -func LoadAndBuild(configPaths []string) error { - return loader.LoadAndBuild(configPaths) -} - // SetCurrentServer sets the current server using composite key: "deploymentName.serverName" // If compositeKey is empty, it will automatically use the first deployment and server available // Example: SetCurrentServer("order-service.order-api") diff --git a/lokstra_registry/helper.go b/lokstra_registry/helper.go index 231e1da2..07a7fea7 100644 --- a/lokstra_registry/helper.go +++ b/lokstra_registry/helper.go @@ -6,29 +6,25 @@ import ( "time" "github.com/primadi/lokstra/common/utils" + "github.com/primadi/lokstra/core/deploy/loader" ) // ===== LEGACY API (For Backward Compatibility) ===== // RunServerFromConfig loads configuration from specified YAML file(s) and runs the server. func RunServerFromConfig(config ...string) { - - if len(config) == 0 { - config = []string{"config.yaml"} - } - // 1. Load config (loads ALL deployments into Global registry) - if err := LoadAndBuild(config); err != nil { + if err := LoadConfig(config...); err != nil { log.Fatal("❌ Failed to load config:", err) } server := GetConfig("server", "") - // if server == "" { - // log.Fatal("❌ 'server' not specified in config, Please add this to your config.yaml:\n" + - // "configs:\n" + - // " server: ${SERVER} # mandatory, default first_server_defined\n" + - // " shutdown_timeout: ${SHUTDOWN_TIMEOUT:30s} # optional, default 30s") - // } + if server == "" { + log.Fatal("❌ 'server' not specified in config, Please add this to your config.yaml:\n" + + "configs:\n" + + " server: ${SERVER} # mandatory, default first_server_defined\n" + + " shutdown_timeout: ${SHUTDOWN_TIMEOUT:30s} # optional, default 30s") + } var timeout time.Duration @@ -91,7 +87,7 @@ func LoadConfig(configPaths ...string) error { } // Load config (loads ALL deployments into Global registry) - if err := LoadAndBuild(configPaths); err != nil { + if err := loader.LoadAndBuild(configPaths); err != nil { return err } diff --git a/project_templates/02_app_framework/03_enterprise_router_service/README_FLOWS.md b/project_templates/02_app_framework/03_enterprise_router_service/README_FLOWS.md index df5a7d59..e8bf6e3e 100644 --- a/project_templates/02_app_framework/03_enterprise_router_service/README_FLOWS.md +++ b/project_templates/02_app_framework/03_enterprise_router_service/README_FLOWS.md @@ -20,10 +20,10 @@ lokstra_registry.RunServerFromConfigFolder("config") ### New Flow ```go -lokstra_registry.LoadConfigFromFolder("config") +lokstra.LoadConfigFromFolder("config") registerServiceTypes() // Config available here! registerMiddlewareTypes() // Config available here! -lokstra_registry.InitAndRunServer() +lokstra.InitAndRunServer() ``` **Benefits:** Early config loading, services can access config diff --git a/project_templates/02_app_framework/03_enterprise_router_service/main.go b/project_templates/02_app_framework/03_enterprise_router_service/main.go index 267f4d11..5fec3423 100644 --- a/project_templates/02_app_framework/03_enterprise_router_service/main.go +++ b/project_templates/02_app_framework/03_enterprise_router_service/main.go @@ -6,7 +6,6 @@ import ( "github.com/primadi/lokstra" "github.com/primadi/lokstra/core/deploy" - "github.com/primadi/lokstra/lokstra_registry" ) // NEW RECOMMENDED FLOW @@ -28,7 +27,7 @@ func main() { // ===== STEP 1: Load Config ===== // Config is loaded first, making it available for service/middleware registration // This registers lazy load services and deployment structure from YAML - if err := lokstra_registry.LoadConfigFromFolder("config"); err != nil { + if err := lokstra.LoadConfigFromFolder("config"); err != nil { log.Fatal("❌ Failed to load config:", err) } @@ -50,7 +49,7 @@ func main() { // - Select server based on config (or auto-select first server) // - Read shutdown timeout from config // - Start the server - if err := lokstra_registry.InitAndRunServer(); err != nil { + if err := lokstra.InitAndRunServer(); err != nil { log.Fatal("❌ Failed to run server:", err) } } diff --git a/tools/migration_runner/example/example_multi_db.go b/tools/migration_runner/example/example_multi_db.go index 86dfb5f1..721079d1 100644 --- a/tools/migration_runner/example/example_multi_db.go +++ b/tools/migration_runner/example/example_multi_db.go @@ -4,7 +4,6 @@ import ( "log" "github.com/primadi/lokstra" - "github.com/primadi/lokstra/lokstra_registry" ) // Example: Multi-database migration setup @@ -14,7 +13,7 @@ func main() { lokstra.Bootstrap() // load database and other configurations - if err := lokstra_registry.LoadConfigFromFolder("config"); err != nil { + if err := lokstra.LoadConfigFromFolder("config"); err != nil { log.Fatalf("Failed to load config: %v", err) } @@ -53,7 +52,7 @@ func main() { // lokstra migration status -dir multi_db/ledger-db // Start your application servers - if err := lokstra_registry.InitAndRunServer(); err != nil { + if err := lokstra.InitAndRunServer(); err != nil { log.Fatalf("Failed to start server: %v", err) } }