Documentation
¶
Overview ¶
Package bootstrap orchestrates the sequential initialization and LIFO cleanup of application components at startup.
Env is always initialized first; Log is always initialized second and closed absolutely last so that all cleanup log messages are captured before the process exits. All other components are registered via App.Add or App.AddParallel and participate in LIFO cleanup.
Basic usage:
bootstrap.New(
env.Component("config/app.toml", &configFS),
log.Component(),
).
AddParallel(dbComp.Component()).
PreReady(migrate).
PreReady(initServices).
Add(ginComp.Component(mount)).
Add(httpComp.Component(func() http.Handler { return router })).
PostReady(func() { slog.Info("server ready") }).
Run()
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type App ¶
type App struct {
// contains filtered or unexported fields
}
App is the startup orchestrator. It manages the ordered initialization and LIFO cleanup of application components.
Close order guarantee:
- Add/AddParallel components in LIFO order
- envComp.Close() (usually no-op)
- logComp.Close() (absolutely last — flushes the async log buffer)
func New ¶
func New(envComp IComponent, logComp IComponent) *App
New creates a new App with mandatory foundation components.
envComp is initialized first (all other components depend on configuration). logComp is initialized second and closed absolutely last so that all cleanup log messages are captured before the process exits.
Both are passed as constructor parameters rather than Add() calls to enforce the ordering constraint at compile time.
func (*App) Add ¶
func (a *App) Add(cs ...IComponent) *App
Add appends one or more components to the sequential startup chain. Components are initialized in registration order and closed in LIFO order.
func (*App) AddParallel ¶
func (a *App) AddParallel(cs ...IComponent) *App
AddParallel appends a group of components that initialize concurrently. All components in the group must succeed before the next phase begins. On shutdown, the group's components are closed concurrently as a unit.
func (*App) PostReady ¶ added in v0.1.15
PostReady registers a callback that is invoked after all steps succeed and before the process blocks waiting for an OS signal. Multiple calls accumulate; callbacks run in registration order. Use it to log a "server ready" message or register with a service-discovery system.
Example ¶
ExampleApp_PostReady shows how to register multiple post-startup callbacks. Each PostReady call appends a callback; all run in registration order after every step succeeds and before the process blocks waiting for an OS signal.
Multiple PostReady calls are useful when separate concerns each need a post-startup hook independently:
bootstrap.New(envComp.Component(...), logComp.Component()).
AddParallel(dbComp.Component()).
Add(ginComp.Component(mount)).
Add(httpComp.Component(handler)).
PostReady(func() { slog.Info("server ready", "addr", ":8080") }).
PostReady(func() { discovery.Register(serviceID) }).
Run()
package main
import (
"fmt"
"github.com/phcp-tech/common-library-golang/bootstrap"
)
func main() {
app := bootstrap.New(
bootstrap.Func("env", nil, nil),
bootstrap.Func("log", nil, nil),
).
PostReady(func() { fmt.Println("first") }).
PostReady(func() { fmt.Println("second") }).
PostReady(func() { fmt.Println("third") })
fmt.Println(app != nil)
}
Output: true
func (*App) PreReady ¶ added in v0.1.15
PreReady registers a setup function that runs inline in the startup sequence, in registration order relative to Add/AddParallel calls. A non-nil error aborts startup identically to a failed Init(). Multiple calls accumulate; functions run in registration order. PreReady steps have no Close and do not participate in LIFO shutdown.
Example ¶
ExampleApp_PreReady shows how to register inline setup functions that run in the startup sequence before the HTTP server starts. Each PreReady call appends a step; steps run in registration order relative to Add/AddParallel calls. A non-nil error aborts startup identically to a failed component Init().
bootstrap.New(envComp.Component(...), logComp.Component()).
AddParallel(dbComp.Component()).
PreReady(migrate). // runs after DB is ready
PreReady(initServices). // runs after migrate
Add(ginComp.Component(mount)).
Add(httpComp.Component(handler)).
Run()
package main
import (
"fmt"
"github.com/phcp-tech/common-library-golang/bootstrap"
)
func main() {
app := bootstrap.New(
bootstrap.Func("env", nil, nil),
bootstrap.Func("log", nil, nil),
).
PreReady(func() error { return nil }).
PreReady(func() error { return nil })
fmt.Println(app != nil)
}
Output: true
func (*App) Run ¶
func (a *App) Run()
Run initializes all components, waits for a shutdown signal, then closes all components in reverse order.
On Init failure: rolls back already-initialized components in LIFO order, flushes the log buffer, then calls os.Exit(1). Panics in the main goroutine are recovered, written to stderr, and exit with code 2.
type IComponent ¶
type IComponent interface {
// Name returns the component name used in log messages.
Name() string
// Init performs initialization. A non-nil error aborts startup,
// triggers rollback of already-started components, and exits the process.
Init() error
// Close releases resources. Called during shutdown in LIFO order.
// Must never panic or block indefinitely.
Close()
}
Component is the lifecycle unit managed by App. Init is called during startup in registration order. Close is called during shutdown in LIFO order and must never fail.
func Func ¶
func Func(name string, init func() error, close func()) IComponent
Func creates an IComponent from an init/close function pair. close may be nil when no cleanup is needed.
Example ¶
ExampleFunc shows how to create a simple IComponent from a pair of functions. close may be nil when no cleanup is needed.
package main
import (
"fmt"
"github.com/phcp-tech/common-library-golang/bootstrap"
)
func main() {
c := bootstrap.Func("my-service",
func() error {
// initialise service
return nil
},
func() {
// release resources
},
)
fmt.Println(c.Name())
fmt.Println(c.Init())
}
Output: my-service <nil>