Documentation
¶
Overview ¶
Package lifecycle supervises ordered module setup, concurrent services and explicitly admitted workers within one shutdown budget. It owns cancellation and reverse teardown, not signal subscriptions, process exit or raw goroutines. Callbacks and the injected logger must cooperate: abandonment bounds Run's return, but cannot kill callbacks or reclaim their resources.
Example ¶
package main
import (
"context"
"fmt"
"io"
"log/slog"
"os"
"syscall"
"go.auvem.com/corestack/lifecycle"
)
func main() {
signals := make(chan os.Signal, 2)
app, err := lifecycle.New(lifecycle.Config{Logger: slog.New(slog.NewTextHandler(io.Discard, nil)), Signals: signals})
if err != nil {
panic(err)
}
ready := make(chan struct{}, 2)
for _, name := range []string{"daemon", "muxer"} {
err := app.Register(lifecycle.Module{
Name: name,
Setup: func(ctx context.Context) error {
return app.Go(ctx, name+" worker", func(ctx context.Context) error { <-ctx.Done(); return ctx.Err() })
},
Run: func(ctx context.Context) error { ready <- struct{}{}; <-ctx.Done(); return ctx.Err() },
Teardown: func(context.Context) error { return nil },
})
if err != nil {
panic(err)
}
}
go func() { <-ready; <-ready; signals <- syscall.SIGTERM }()
fmt.Println(app.Run(context.Background()))
}
Output: <nil>
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 a single-use coordinator constructed by New. Do not copy it. Register modules before Run; Go may be called concurrently during setup and running. App stores no context. After abandonment, callers own process exit and must not reuse resources whose callbacks have not returned.
func (*App) Go ¶
Go immediately launches and tracks fn, or returns an admission error without launching it. ctx must be a callback's lifecycle context or a descendant; ancestry is a caller precondition and cannot generally be checked. Detached contexts forfeit graceful cancellation. Names are diagnostic and may repeat. Callers must handle rejection; raw goroutines are outside App's guarantee.
func (*App) Register ¶
Register captures a uniquely named module with required setup and teardown. Registration closes permanently when Run begins, including a failed run.
func (*App) Run ¶
Run sets up modules in registration order, then runs services concurrently. Every service and admitted worker must finish for normal completion. The first failure, parent cancellation or signal cancels their shared context and closes admission before reverse teardown. A fresh context retains parent values and gives teardown and callback completion one deadline from the shutdown trigger. In-flight setup is awaited within that budget before rollback; abandoned setup is never torn down later. Deadline or second signal abandons outstanding work. Observed failures are joined; expected callback cancellation during established shutdown is omitted only for cancellation-only error trees. Mixed errors remain intact to preserve wrapper types, identity and matching, so may still match cancellation. Initiating failures and every teardown error remain. Cancellation is omitted only when context.Cause proves App caused it; parent propagation and independently canceled descendants are retained conservatively. Run never recovers panics, closes Signals or exits the process.
type Config ¶
type Config struct {
// Logger receives lifecycle diagnostics and must not block.
Logger *slog.Logger
// Signals is a caller-owned, filtered signal source.
Signals <-chan os.Signal
// ShutdownTimeout bounds all shutdown work together.
ShutdownTimeout time.Duration
}
Config supplies application policy. Logger is required and must not block. Zero ShutdownTimeout selects 30 seconds; negative values are invalid. The caller owns Signals, its subscription and cleanup, filtering to SIGINT and SIGTERM and buffering at least two signals. Nil or closed disables reception.
type Module ¶
type Module struct {
// Name identifies the module in errors.
Name string
// Setup acquires resources before any service starts.
Setup func(context.Context) error
// Teardown releases resources after successful Setup.
Teardown func(context.Context) error
// Run optionally serves until completion or cancellation.
Run func(context.Context) error
}
Module describes one resource owner. Setup acquires resources; Teardown releases them after successful setup. A failing Setup owns its partial cleanup. Optional Run starts only after all setups succeed. Callbacks must honor cancellation.