Documentation
¶
Overview ¶
Package signal provides a stateful signal context with introspection and LIFO hooks.
It solves two main problems for CLI applications:
- Distinguishing between SIGINT (soft interrupt) and SIGTERM (hard termination).
- Managing cleanup operations (Hooks) in a reliable, observable way.
Dual Signal Handling ¶
Unlike standard signal.NotifyContext, this package allows configuring SIGINT to initiate a graceful shutdown logic rather than immediate cancellation. Repeated signals can trigger a "Force Exit" (os.Exit(1)) to prevent hung processes.
Lifecycle Hooks ¶
Users can register cleanup functions via Context.OnShutdown. These hooks execution is guaranteed to run in LIFO (Last-In-First-Out) order, simulating `defer`.
This package is the foundation of the Lifecycle Data Plane. It establishes the core context propagation and cleanup contracts.
Index ¶
- func MermaidState(s State) string
- func PrimaryLabeler(state any) string
- func PrimaryStyler(state any) string
- type Config
- type Context
- func (sc *Context) Cancel()
- func (sc *Context) ComponentType() string
- func (sc *Context) ForceExitThreshold() int
- func (sc *Context) IsUnsafe() bool
- func (sc *Context) OnShutdown(f func())
- func (sc *Context) Reason() Reason
- func (sc *Context) ResetSignalCount()
- func (sc *Context) Shutdown()
- func (sc *Context) ShutdownWait()
- func (sc *Context) Signal() os.Signal
- func (sc *Context) State() State
- func (sc *Context) Stop()
- func (sc *Context) Wait()
- func (sc *Context) Watch(ctx context.Context) <-chan introspection.StateChange[State]
- type Option
- type Reason
- type State
- type Status
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func MermaidState ¶
MermaidState returns a Mermaid state diagram string representing the lifecycle configuration.
func PrimaryLabeler ¶
PrimaryLabeler builds the HTML label for the signal component.
func PrimaryStyler ¶
PrimaryStyler determines the CSS class for the signal component based on its state.
Types ¶
type Config ¶
State represents the configuration state of the SignalContext. Config represents immutable signal handler configuration. These values are set at initialization and never change during runtime.
type Context ¶
Context wraps a context and captures the signal that cancelled it.
func FromContext ¶
FromContext retrieves the signal.Context from a possibly wrapped context.
func NewContext ¶
NewContext creates a context that is cancelled on SIGTERM or SIGINT (standard termination). On the first signal received, it cancels the context to initiate graceful shutdown (if configured). If a second signal is received before the program exits, it performs an immediate os.Exit(1) (if configured).
func (*Context) ComponentType ¶
ComponentType returns the component type for introspection.
func (*Context) ForceExitThreshold ¶
ForceExitThreshold returns the number of signals required to trigger os.Exit(1).
func (*Context) IsUnsafe ¶
IsUnsafe returns true if the context is configured to never force exit (threshold 0).
func (*Context) OnShutdown ¶
func (sc *Context) OnShutdown(f func())
OnShutdown registers a function to be called when the context receives a shutdown signal. Hooks are executed in LIFO (Last-In-First-Out) order, simulating `defer`. Execution happens asynchronously after the context is cancelled. Call Wait() to block until all hooks (including those registered dynamically) have finished.
func (*Context) ResetSignalCount ¶
func (sc *Context) ResetSignalCount()
ResetSignalCount resets the signal counter and clears the last received signal. This is useful for "Smart Handlers" that successfully handle a signal (e.g. Suspend) and want to reset the "Force Exit" threshold.
func (*Context) Shutdown ¶
func (sc *Context) Shutdown()
Shutdown is an alias for Cancel for consistency with other components.
func (*Context) ShutdownWait ¶
func (sc *Context) ShutdownWait()
ShutdownWait initiates a graceful shutdown and blocks until all hooks have completed. It is a shorthand for Shutdown() followed by Wait().
func (*Context) Signal ¶
Signal returns the signal that caused the context to be cancelled/interrupted, or nil.
func (*Context) Stop ¶
func (sc *Context) Stop()
Stop stops the signal monitoring and restores default behavior. It also ensures Wait() unblocks if called.
func (*Context) Wait ¶
func (sc *Context) Wait()
Wait blocks until all registered hooks have completed execution. This is essential to prevent the main function from exiting before cleanup is done.
func (*Context) Watch ¶
func (sc *Context) Watch(ctx context.Context) <-chan introspection.StateChange[State]
Watch implements introspection.TypedWatcher[State] interface. Returns a type-safe channel that emits StateChange[State] events. The channel is closed when the provided context is cancelled.
type Option ¶
type Option func(*options)
Option is a functional option for configuring signal behavior.
func WithCancelOnInterrupt ¶
WithCancelOnInterrupt controls whether SIGINT cancels the context.
true (default): SIGINT immediately cancels context (traditional behavior)
- Use for: CLIs, servers, batch jobs
- SIGINT #1: Context cancelled (graceful shutdown)
- SIGINT #2+: Force exit based on threshold
false: SIGINT only emits events, does NOT cancel context
- Use for: REPLs, interactive shells, suspendable processes
- SIGINT #1-N: Emits control events (ClearLine, Suspend, etc.)
- SIGINT #N: Force exit when threshold reached
- User must explicitly cancel context via router/handler
Note: SIGTERM always cancels context regardless of this setting.
func WithForceExit ¶
WithForceExit configures the threshold of signals required to trigger an immediate os.Exit(1). Threshold values: 1 (Default): SIGINT cancels context immediately. SIGTERM always cancels. n >= 2: SIGINT is captured (signalCount increments), os.Exit(1) at n-th signal. 0 (Unsafe): Automatic os.Exit(1) is disabled for SIGINT. SIGTERM still cancels context.
func WithHookTimeout ¶
WithHookTimeout configures the duration after which a running hook produces a warning log. Default is 5 seconds.
func WithResetTimeout ¶
WithResetTimeout configures the duration after which the signal count resets. If a signal is received after this duration from the previous one, it is treated as a new sequence. Default is 5 seconds.
type Reason ¶
type Reason string
Reason describes why the context was cancelled.
const ( ReasonNone Reason = "None" ReasonInterrupt Reason = "Signal:Interrupt" // SIGINT (Ctrl+C) ReasonTerminate Reason = "Signal:Terminate" // SIGTERM ReasonManualStop Reason = "Manual:Stop" // Explicit Stop() call ReasonManualCancel Reason = "Manual:Cancel" // Context Cancel() called ReasonTimeout Reason = "System:Timeout" // Shutdown timed out )
type State ¶
State combines configuration and runtime status for introspection. This struct is used for type-safe state watching and diagram generation.
type Status ¶
type Status struct {
Received os.Signal
Reason Reason
Stopping bool // Context is cancelled, hooks may be running
SignalCount int
ResetDeadline time.Time
Enabled bool // Monitoring loop is active (shielding escalation)
Stopped bool // All shutdown hooks have finished
}
Status represents dynamic signal handler runtime state. These values change as the handler processes signals and manages lifecycle.