signal

package
v1.6.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 17, 2026 License: AGPL-3.0 Imports: 11 Imported by: 0

Documentation

Overview

Package signal provides a stateful signal context with introspection and LIFO hooks.

It solves two main problems for CLI applications:

  1. Distinguishing between SIGINT (soft interrupt) and SIGTERM (hard termination).
  2. 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

Constants

This section is empty.

Variables

This section is empty.

Functions

func MermaidState

func MermaidState(s State) string

MermaidState returns a Mermaid state diagram string representing the lifecycle configuration.

func PrimaryLabeler

func PrimaryLabeler(state any) string

PrimaryLabeler builds the HTML label for the signal component.

func PrimaryStyler

func PrimaryStyler(state any) string

PrimaryStyler determines the CSS class for the signal component based on its state.

Types

type Config

type Config struct {
	ForceExitThreshold int
	HookTimeout        time.Duration
}

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

type Context struct {
	context.Context
	// contains filtered or unexported fields
}

Context wraps a context and captures the signal that cancelled it.

func FromContext

func FromContext(ctx context.Context) (*Context, bool)

FromContext retrieves the signal.Context from a possibly wrapped context.

func NewContext

func NewContext(parent context.Context, opts ...Option) *Context

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) Cancel

func (sc *Context) Cancel()

Cancel terminates the context manually.

func (*Context) ComponentType

func (sc *Context) ComponentType() string

ComponentType returns the component type for introspection.

func (*Context) ForceExitThreshold

func (sc *Context) ForceExitThreshold() int

ForceExitThreshold returns the number of signals required to trigger os.Exit(1).

func (*Context) IsUnsafe

func (sc *Context) IsUnsafe() bool

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) Reason

func (sc *Context) Reason() Reason

Reason returns the reason why the context was cancelled.

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

func (sc *Context) Signal() os.Signal

Signal returns the signal that caused the context to be cancelled/interrupted, or nil.

func (*Context) State

func (sc *Context) State() State

State returns a snapshot of the current configuration.

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

func WithCancelOnInterrupt(enabled bool) Option

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

func WithForceExit(threshold int) Option

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

func WithHookTimeout(d time.Duration) Option

WithHookTimeout configures the duration after which a running hook produces a warning log. Default is 5 seconds.

func WithResetTimeout

func WithResetTimeout(d time.Duration) Option

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
)

func (Reason) String

func (r Reason) String() string

type State

type State struct {
	Config
	Status
}

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL