Application lifecycle manager enforcing a three-phase init/wire/start sequence with reverse-order graceful shutdown and per-component stop timeouts. What's included: - `Component` interface (OnInit / OnStart / OnStop) and `Hook` type for BeforeStart wiring functions - `Launcher` interface with Append, BeforeStart, Run (blocks on SIGINT/SIGTERM), and idempotent Shutdown(ctx) - `New(logger, opts...)` constructor with configurable ComponentStopTimeout (default 15 s); no global state Tested-via: todo-api POC integration Reviewed-against: docs/adr/
2.8 KiB
2.8 KiB
Changelog
All notable changes to this module will be documented in this file.
The format is based on Keep a Changelog, and this module adheres to Semantic Versioning.
0.9.0 - 2026-03-18
Added
Componentinterface —OnInit() error(open connections, allocate resources),OnStart() error(start background goroutines and listeners),OnStop() error(graceful shutdown and resource release)Hooktype —func() errorused to register dependency-injection wiring functions that run betweenOnInitandOnStartOptionsstruct —ComponentStopTimeout time.Duration(maximum time allowed for each component'sOnStop; default 15 seconds); zero value is validLauncherinterface —Append(components ...Component),BeforeStart(hooks ...Hook),Run() error,Shutdown(ctx context.Context) errorNew(logger logz.Logger, opts ...Options) Launcher— constructs aLauncher; no package-level singletons or global state; variadic opts apply the first element if providedLauncher.Append— registers one or more components in order; startup proceeds in registration order, shutdown in reverseLauncher.BeforeStart— registers hooks that run after allOnInitcalls complete and before anyOnStartcall; correct place for dependency injection wiringLauncher.Run() error— executes the full lifecycle (OnInit → BeforeStart hooks → OnStart → wait → reverse-order OnStop); blocks untilSIGINT,SIGTERM, orShutdownis calledLauncher.Shutdown(ctx context.Context) error— triggers a graceful shutdown programmatically and waits forRunto return; idempotent viasync.Once, safe to call from multiple goroutines; ctx controls the caller-side wait timeout only- OS signal handling for
SIGINTandSIGTERMbuilt intoRunwith automaticsignal.Stopcleanup on return - Per-component independent stop timeout: each component's
OnStopruns in its own goroutine and is abandoned (with an error log) if it exceedsComponentStopTimeout
Design Notes
- The three-phase lifecycle (OnInit / BeforeStart / OnStart) cleanly separates resource allocation from dependency wiring from service activation, ensuring no component begins serving traffic before all its dependencies are fully initialized.
- Shutdown runs in strict reverse registration order with a per-component independent timeout, so a stalled component cannot block others from stopping; worst-case shutdown time is
n × ComponentStopTimeout. Shutdowncloses a channel viasync.Oncerather than using a mutex or flag, making it genuinely safe to call concurrently from an OS signal handler and a test teardown racing against each other.