Documentation
¶
Overview ¶
Package component defines the core interfaces for lifecycle-managed infrastructure services in gokit.
Components represent services that require initialization, startup, shutdown, and health monitoring. They are registered with the bootstrap package for automatic lifecycle management.
Interfaces ¶
- Component: Core lifecycle interface (Init/Start/Stop)
- HealthChecker: Health status reporting
- Describable: Bootstrap summary descriptions
Index ¶
- Constants
- type BaseLazyComponent
- func (b *BaseLazyComponent) Close() error
- func (b *BaseLazyComponent) HealthCheck(ctx context.Context) error
- func (b *BaseLazyComponent) Initialize(ctx context.Context) error
- func (b *BaseLazyComponent) IsInitialized() bool
- func (b *BaseLazyComponent) Name() string
- func (b *BaseLazyComponent) WithCloser(fn func() error) *BaseLazyComponent
- func (b *BaseLazyComponent) WithHealthCheck(fn func(context.Context) error) *BaseLazyComponent
- type Component
- type Describable
- type Description
- type Health
- type HealthStatus
- type LazyComponent
- type Registry
- func (r *Registry) All() []Component
- func (r *Registry) Get(name string) Component
- func (r *Registry) HealthAll(ctx context.Context) []Health
- func (r *Registry) Register(c Component) error
- func (r *Registry) StartAll(ctx context.Context) error
- func (r *Registry) StartAllConcurrent(ctx context.Context) error
- func (r *Registry) State(name string) (State, bool)
- func (r *Registry) StopAll(ctx context.Context) error
- func (r *Registry) StopAllDetailed(ctx context.Context) []StopResult
- type RegistryConfig
- type Route
- type RouteProvider
- type State
- type StopResult
Constants ¶
const DefaultStartTimeout = 30 * time.Second
DefaultStartTimeout bounds a single component's Start call when the caller-supplied context has no deadline. The bound is cooperative — Start must return when its context is canceled (see Component.Start); it caps a well-behaved Start, not one that ignores ctx.
const DefaultStopTimeout = 10 * time.Second
DefaultStopTimeout is applied to a component's Stop call only when the caller-supplied context has no deadline. A bounded fallback prevents a stuck Stop from blocking shutdown forever, while still letting callers pass a tighter deadline by attaching one to ctx.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type BaseLazyComponent ¶
type BaseLazyComponent struct {
// contains filtered or unexported fields
}
BaseLazyComponent provides thread-safe lazy initialization for components that defer expensive setup until first use.
func NewBaseLazyComponent ¶
func NewBaseLazyComponent(name string, initializer func(context.Context) error) *BaseLazyComponent
NewBaseLazyComponent creates a lazy component with the given initializer.
func (*BaseLazyComponent) Close ¶
func (b *BaseLazyComponent) Close() error
Close shuts down the component and marks it as uninitialized.
func (*BaseLazyComponent) HealthCheck ¶
func (b *BaseLazyComponent) HealthCheck(ctx context.Context) error
HealthCheck verifies the component is initialized and optionally runs a custom check.
func (*BaseLazyComponent) Initialize ¶
func (b *BaseLazyComponent) Initialize(ctx context.Context) error
Initialize performs thread-safe lazy initialization using double-check locking.
func (*BaseLazyComponent) IsInitialized ¶
func (b *BaseLazyComponent) IsInitialized() bool
IsInitialized returns whether the component has been successfully initialized.
func (*BaseLazyComponent) Name ¶
func (b *BaseLazyComponent) Name() string
Name returns the component name.
func (*BaseLazyComponent) WithCloser ¶
func (b *BaseLazyComponent) WithCloser(fn func() error) *BaseLazyComponent
WithCloser sets a custom close function.
func (*BaseLazyComponent) WithHealthCheck ¶
func (b *BaseLazyComponent) WithHealthCheck(fn func(context.Context) error) *BaseLazyComponent
WithHealthCheck sets a custom health check function.
type Component ¶
type Component interface {
// Name returns the unique name of the component for registration.
Name() string
// Start initializes and starts the component. Implementations must honor ctx:
// return promptly when ctx is canceled or its deadline passes. The registry derives a
// bounded context for each Start (RegistryConfig.StartTimeout) and cancels peers when a
// sibling fails, but Go cannot interrupt a synchronous call that ignores its context, so
// a Start that blocks without observing ctx will stall the boot sequence.
Start(ctx context.Context) error
// Stop gracefully shuts down the component and releases resources.
// Implementations must drain inflight work within the context deadline.
Stop(ctx context.Context) error
// Health returns the current health status of the component.
Health(ctx context.Context) Health
}
Component represents a lifecycle-managed infrastructure component. Each infrastructure module (database, redis, kafka, etc.) implements this interface.
The canonical lifecycle state machine is:
Created → Starting → Running → Stopping → Stopped
↘ Failed
Stop() is responsible for draining any inflight work before releasing resources. The framework enforces a per-component timeout via the context.
type Describable ¶
type Describable interface {
Describe() Description
}
Describable is optionally implemented by Components to provide startup summary information for the bootstrap display.
When a component implements this interface, the bootstrap system automatically includes it in the infrastructure section of the startup summary — no manual TrackInfrastructure calls needed.
IMPROVE-RSKIT: rskit's component trait is lifecycle-only; these optional self-description capabilities (Describable/RouteProvider) are a gokit enhancement. Consider adding equivalent optional metadata traits to rskit-component so the two kits report startup summaries at parity.
type Description ¶
type Description struct {
// Name is the human-readable display name (e.g., "HTTP Server", "PostgreSQL"). If empty,
// the component's Name() is used.
Name string
// Type categorizes the component: "database", "server", "kafka", "redis", etc.
Type string
// Details is a human-readable one-liner shown in the startup summary. Examples:
// "localhost:5432 pool=25/5", "localhost:6379 db=0 pool=10"
Details string
// Port is the primary port, 0 if not applicable.
Port int
}
Description holds summary information for the bootstrap display. Components that implement Describable return this to self-report what they are and how they're configured.
type Health ¶
type Health struct {
Name string `json:"name"`
Status HealthStatus `json:"status"`
Message string `json:"message,omitempty"`
}
Health holds health information for a component.
func Degraded ¶
Degraded returns a degraded report for the named component with an explanatory message.
type HealthStatus ¶
type HealthStatus string
HealthStatus represents the health state of a component.
const ( StatusHealthy HealthStatus = "healthy" StatusUnhealthy HealthStatus = "unhealthy" StatusDegraded HealthStatus = "degraded" )
type LazyComponent ¶
type LazyComponent struct {
// contains filtered or unexported fields
}
LazyComponent wraps a component factory so the underlying Component is not constructed until Start is first called. This defers expensive construction (opening connections, allocating pools) out of registration and into the boot sequence, while still presenting a normal Component to the Registry.
It differs from BaseLazyComponent, which defers an initializer on an already-constructed component; LazyComponent defers construction of the Component itself.
func NewLazyComponent ¶
func NewLazyComponent(name string, factory func() Component) *LazyComponent
NewLazyComponent returns a LazyComponent that builds its delegate via factory on first Start.
func (*LazyComponent) Health ¶
func (l *LazyComponent) Health(ctx context.Context) Health
Health reports the delegate's health, or a degraded "not started" report before first Start.
func (*LazyComponent) Start ¶
func (l *LazyComponent) Start(ctx context.Context) error
Start constructs the delegate (once) and starts it. A nil factory, or a factory that returns a nil Component — including a typed nil such as a nil *T stored in the interface, which a plain == nil check misses — yields a typed error rather than a panic: Go interfaces permit nil values that the Rust Arc<dyn Component> counterpart cannot, so this lifecycle path guards them explicitly.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry manages component lifecycle with deterministic ordering. Components are started in registration order and stopped in reverse order. Each component tracks a formal lifecycle state (Created → Starting → Running → Stopping → Stopped | Failed).
func NewRegistry ¶
func NewRegistry() *Registry
NewRegistry creates a new component registry with default configuration.
func NewRegistryWithConfig ¶
func NewRegistryWithConfig(cfg RegistryConfig) *Registry
NewRegistryWithConfig creates a component registry with the given configuration. Zero fields fall back to the registry defaults.
func (*Registry) HealthAll ¶
HealthAll returns health status for all registered components. The snapshot is taken under the read lock, but Health() calls are made without holding the lock to avoid blocking registration or lifecycle ops.
func (*Registry) Register ¶
Register adds a component to the registry. Components are started in the order they are registered, so register dependencies first.
func (*Registry) StartAll ¶
StartAll starts all not-yet-started components in registration order.
It is safe to call multiple times — already-running components are skipped. This supports two-phase startup where infrastructure components are started first and application-layer components (registered during configure) are started in a second pass.
If a component fails to start, all components that were successfully started during this call are rolled back (stopped in reverse order). Components started by a previous call are NOT rolled back.
The Component.Start call runs without holding any registry lock so readers (Get / All / HealthAll) and concurrent Register calls are not blocked for the duration of the boot sequence.
Each Component.Start is given a context bounded by RegistryConfig.StartTimeout when the supplied context carries no deadline; pass a context with an explicit deadline to override that bound. The bound is cooperative: Start must observe its context and return when it is canceled (see Component.Start). Go cannot interrupt a synchronous call that ignores its context, so a component that never returns on cancellation can still stall the boot sequence — the timeout bounds well-behaved components, it is not a hard kill.
func (*Registry) StartAllConcurrent ¶
StartAllConcurrent starts all not-yet-started components in parallel, bounded by RegistryConfig.Concurrency (zero means no limit). Unlike StartAll it does not impose a registration order between components, so use it only when the registered components have no inter-dependencies. On any failure it stops every component started during this call (in reverse completion order) and returns the first start error.
func (*Registry) State ¶
State returns the lifecycle state of a named component. Returns StateCreated and false if the component is not registered.
func (*Registry) StopAll ¶
StopAll gracefully stops all running components in reverse registration order.
Each Component.Stop runs with the caller's ctx; if ctx has no deadline, DefaultStopTimeout is applied per-component as a safety net. Errors are aggregated via errors.Join so callers can inspect individual failures with errors.Is/errors.As.
func (*Registry) StopAllDetailed ¶
func (r *Registry) StopAllDetailed(ctx context.Context) []StopResult
StopAllDetailed gracefully stops all running components and returns per-component results. This provides structured error information for callers that need to know which specific components failed.
type RegistryConfig ¶
type RegistryConfig struct {
// Concurrency is the maximum number of components started in parallel by
// StartAllConcurrent. Zero means "no limit" (start every candidate at once).
// Sequential StartAll ignores this field.
Concurrency int
// StartTimeout bounds each component's Start call when ctx has no deadline.
StartTimeout time.Duration
// StopTimeout bounds each component's Stop call when ctx has no deadline.
StopTimeout time.Duration
}
RegistryConfig configures a component Registry: how many components may start in parallel and the per-component start/stop timeouts applied when the caller's context carries no deadline.
func DefaultRegistryConfig ¶
func DefaultRegistryConfig() RegistryConfig
DefaultRegistryConfig returns the registry defaults: sequential start (Concurrency 1) with bounded start and stop timeouts.
type RouteProvider ¶
type RouteProvider interface {
Routes() []Route
}
RouteProvider is optionally implemented by server components to auto-report registered HTTP routes for the startup summary.
type State ¶
type State int
State represents the lifecycle state of a component.
const ( // StateCreated is the initial state after registration. StateCreated State = iota // StateStarting indicates the component is currently starting. StateStarting // StateRunning indicates the component started successfully and is operational. StateRunning // StateStopping indicates the component is currently shutting down. StateStopping // StateStopped indicates the component has been shut down. StateStopped // StateFailed indicates the component failed to start or encountered a fatal error. StateFailed )
type StopResult ¶
type StopResult struct {
// Name of the component.
Name string
// Err is nil on success, non-nil on failure.
Err error
}
StopResult holds the outcome of stopping a single component.