Application Lifecycle
Understanding the Goose application lifecycle helps you hook into key stages of your application's execution.
Lifecycle Overview
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Application Start โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 1. Platform Creation โ
โ - Create platform (API/Web/CLI) โ
โ - Load platform configuration โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 2. Container Initialization โ
โ - Create IoC container โ
โ - Register core services โ
โ - Run initializers โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 3. Module Traversal โ
โ - Resolve module imports โ
โ - Register declarations โ
โ - Publish exports โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 4. Boot Hooks โ
โ - Execute OnBoot hooks โ
โ - Initialize routes โ
โ - Start background services โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 5. Platform Boot โ
โ - Start HTTP server (API/Web) โ
โ - Execute commands (CLI) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 6. Application Running โ
โ - Handle requests โ
โ - Process jobs โ
โ - Run cron tasks โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 7. Shutdown โ
โ - Stop accepting requests โ
โ - Complete pending operations โ
โ - Execute cleanup hooks โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Lifecycle Hooks
Boot Hook
Execute code after the application is fully initialized but before it starts running.
Implement the types.Bootable interface:
type MyService struct {
db *sql.Db `inject:""`
cache *cache.Cache `inject:""`
}
// Boot is called during the boot phase
func (s *MyService) Boot(k types.Kernel) error {
// Warm up cache
// ...
// Verify database connection
// ...
return nil
}
Shutdown Hook
Execute cleanup code when the application shuts down.
Implement the types.Shutdownable interface:
func (s *MyService) Shutdown(k types.Kernel) error {
// Close connections
// Flush buffers
// Save state
return nil
}
Hook Interfaces
// types/hooks.go
// Configurable is called during module registration, before declarations are created.
type Configurable interface {
Configure(c Container) error
}
// Bootable is implemented by services that need initialization after setup
type Bootable interface {
Boot(k Kernel) error
}
// Shutdownable is implemented by services that need cleanup on shutdown
type Shutdownable interface {
Shutdown(k Kernel) error
}
Using Initializers
Initializers run before module traversal:
func main() {
initializers := []func(types.Container) error{
loadConfiguration,
setupLogging,
validateEnvironment,
}
stop, err := goose.Start(goose.API(platform, module, initializers))
if err != nil {
panic(err)
}
defer stop()
}
func loadConfiguration(container types.Container) error {
config, err := config.Load("./config")
if err != nil {
return err
}
container.Register(func() *config.Config {
return config
}, "", true)
return nil
}
func setupLogging(container types.Container) error {
logger := log.NewLog(
log.AppLogChannel("app"),
log.NewLogger(
[]types.Modifier{},
formatters.NewLine(),
processors.NewConsole(),
),
)
container.Register(func() types.Log {
return logger
}, "", true)
return nil
}
func validateEnvironment(container types.Container) error {
required := []string{"APP_NAME", "DB_DATABASE"}
env := env.NewEnv()
for _, key := range required {
if env.Get(key) == "" {
return fmt.Errorf("missing required env: %s", key)
}
}
return nil
}
Request Lifecycle
For each HTTP request:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Incoming Request โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 1. Request Parsing โ
โ - Parse HTTP method, path, headers โ
โ - Create request context โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 2. Route Matching โ
โ - Find matching route โ
โ - Extract path parameters โ
โ - Collect middleware stack โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 3. Middleware Execution โ
โ - Execute middleware chain โ
โ - Authentication, logging, etc. โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 4. Handler Execution โ
โ - Resolve controller โ
โ - Call handler method โ
โ - Execute business logic โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 5. Response Serialization โ
โ - Serialize return value โ
โ - Set headers โ
โ - Send response โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Graceful Shutdown
Goose handles graceful shutdown automatically:
func main() {
stop, err := goose.Start(goose.API(platform, module, nil))
if err != nil {
panic(err)
}
// The stop function is called when:
// - SIGINT received (Ctrl+C)
// - SIGTERM received (kill)
// - Application error
defer func() {
if err := stop(); err != nil {
log.Println("Shutdown error:", err)
}
}()
}
Custom Shutdown Handling
func main() {
stop, err := goose.Start(goose.API(platform, module, nil))
if err != nil {
panic(err)
}
// Wait for shutdown signal
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
fmt.Println("Shutting down...")
// Custom cleanup
cleanupResources()
// Stop the application
if err := stop(); err != nil {
log.Fatal(err)
}
}
Multi-Instance Lifecycle
For multi-platform applications:
func main() {
stop, err := goose.Start(
goose.API(apiPlatform, apiModule, nil),
goose.Web(webPlatform, webModule, nil),
goose.CLI(cliPlatform, cliModule, nil),
)
if err != nil {
panic(err)
}
defer stop()
}
- API and Web platforms run concurrently
- CLI platform runs when
cliargument is passed - All share the same dependency container
Best Practices
1. Fail Fast
Validate critical requirements during boot:
func (s *DatabaseService) OnBoot(kernel types.Kernel) error {
// Fail immediately if database is unreachable
if err := s.db.Ping(); err != nil {
return fmt.Errorf("database not available: %w", err)
}
return nil
}
2. Clean Shutdown
Always clean up resources:
func (s *QueueService) OnShutdown() error {
// Wait for in-progress jobs
s.queue.WaitForCompletion(30 * time.Second)
// Close connections
return s.connection.Close()
}
3. Health Checks
Implement health checks for production:
func (c *HealthController) Routes() types.Routes {
return types.Routes{
{Method: "GET", Path: "/health", Handler: c.Check},
{Method: "GET", Path: "/ready", Handler: c.Ready},
}
}
func (c *HealthController) Check(ctx types.Context) any {
return map[string]string{"status": "ok"}
}
Next Steps
- Multi-Platform Support - Running multiple platforms
- Middleware - Request interceptors
- Error Handling - Handling errors