Documentation
¶
Overview ¶
Package supervisor runs an application's long-running components (HTTP servers, queue workers, pub/sub listeners, the scheduler and background tasks) as goroutines in one process, and shuts them down gracefully.
A Supervisor provides:
- Roles: each component declares roles such as "http" or "workers", and Supervisor.Run can start only some of them, so one binary can run everything on a small server or be split across machines.
- Restart policies: a failing component can be left stopped (RestartNever), restarted with exponential backoff (RestartOnFailure), or stop the whole application (StopOnFailure). Panics are recovered and treated as failures.
- Staged shutdown: on shutdown, stages are canceled in ascending order (StageIngress first, StageBackground last), each draining before the next is canceled, all within one timeout.
- Health: Supervisor.Ready and Supervisor.Status feed readiness probes and diagnostics.
Most applications use the supervisor through anetos.App (app.Go, app.Component and app.Run) rather than directly.
Concept guide: docs/site/concepts/runtime-supervisor.md.
Index ¶
- Variables
- type Backoff
- type Component
- type ComponentStatus
- type Options
- type PanicError
- type Readier
- type Restart
- type Spec
- type Stage
- type State
- type Supervisor
- func (s *Supervisor) Add(spec Spec) error
- func (s *Supervisor) Declare(roles ...string)
- func (s *Supervisor) Ready() bool
- func (s *Supervisor) Roles() []string
- func (s *Supervisor) Run(ctx context.Context, roles ...string) error
- func (s *Supervisor) ShutdownDeadline() time.Time
- func (s *Supervisor) ShutdownStarted() time.Time
- func (s *Supervisor) Status() []ComponentStatus
Constants ¶
This section is empty.
Variables ¶
var ( // ErrAlreadyRun is returned by [Supervisor.Run] on a second call. ErrAlreadyRun = errors.New("supervisor: Run called more than once") // ErrStopping is returned by [Supervisor.Add] once shutdown has begun. ErrStopping = errors.New("supervisor: shutting down") // ErrShutdownTimeout is wrapped by the error [Supervisor.Run] returns when // components are still running after the shutdown timeout. ErrShutdownTimeout = errors.New("supervisor: shutdown timed out") )
Functions ¶
This section is empty.
Types ¶
type Backoff ¶
type Backoff struct {
// Initial is the delay before the first restart. Default 1s.
Initial time.Duration
// Max caps the delay. Default 30s. A component that ran for longer than
// Max before failing is considered healthy again, and the delay resets.
Max time.Duration
// MaxRestarts limits consecutive restarts; 0 means unlimited.
MaxRestarts int
}
Backoff configures restarts for RestartOnFailure.
type Component ¶
type Component interface {
// Name identifies the component in logs and status; unique per app.
Name() string
// Run does the work until ctx is canceled or the work is done.
Run(ctx context.Context) error
}
Component is a long-running unit of work managed by a Supervisor: an HTTP server, a queue worker pool, a pub/sub listener, the scheduler, or an ad-hoc background task.
Run must block until the work is finished or ctx is canceled. When ctx is canceled, Run should stop taking new work, finish or hand back in-flight work, and return promptly. Returning nil means the component completed normally; returning an error (or panicking) is a failure handled according to the component's Restart policy.
type ComponentStatus ¶
type ComponentStatus struct {
Name string // the component's name
Roles []string // its roles
Stage Stage // its shutdown stage
Restart Restart // its restart policy
State State // what it is doing
Restarts int // restarts performed so far
LastError error // most recent failure, if any
Since time.Time // when State was entered
}
ComponentStatus is a point-in-time snapshot of one component.
type Options ¶
type Options struct {
// Logger receives lifecycle, failure and restart events.
// Default slog.Default().
Logger *slog.Logger
// ShutdownTimeout bounds graceful shutdown across all stages. Default 30s.
ShutdownTimeout time.Duration
}
Options configures a Supervisor.
type PanicError ¶
type PanicError struct {
Value any // the value passed to panic
Stack []byte // the goroutine's stack when it panicked
}
PanicError is the failure recorded when a component panics.
func (*PanicError) Error ¶
func (e *PanicError) Error() string
Error implements the error interface.
type Readier ¶
type Readier interface {
// Ready reports whether the component can take work.
Ready() bool
}
Readier is optionally implemented by components that need time to become ready (for example, an HTTP server that must bind its port). Until Ready returns true, Supervisor.Ready reports false.
type Restart ¶
type Restart int
Restart decides what happens when a component fails (returns an error or panics) while the supervisor is running.
const ( // RestartNever logs the failure and leaves the component stopped. The // rest of the application keeps running. RestartNever Restart = iota // RestartOnFailure restarts the component after an exponential backoff. // If Backoff.MaxRestarts is exceeded, the failure escalates as if the // policy were StopOnFailure. RestartOnFailure // StopOnFailure shuts the whole application down; [Supervisor.Run] // returns the component's error. Use it for components the app cannot // work without, such as the HTTP server. StopOnFailure )
type Spec ¶
type Spec struct {
// Component is what runs.
Component Component
// Roles lists the roles this component belongs to (e.g. "http",
// "workers"). A component with no roles runs in every process.
Roles []string
// Stage orders shutdown: lower stages stop first.
Stage Stage
// Restart says what happens when Run fails (returns an error or
// panics); a nil return is always done.
Restart Restart
// Backoff spaces restarts; the zero value uses the defaults.
Backoff Backoff
}
Spec describes how a component is supervised.
type Stage ¶
type Stage int
Stage orders graceful shutdown. On shutdown the supervisor cancels stages from lowest to highest, waiting for every component in a stage to return before canceling the next. Producers of work stop before its consumers, so consumers can finish what was already produced.
const ( StageIngress Stage = 0 // HTTP servers: stop accepting requests first StageScheduler Stage = 10 // scheduler: stop starting new runs StageListeners Stage = 20 // pub/sub listeners: stop pulling messages StageWorkers Stage = 30 // queue workers: finish in-flight jobs StageBackground Stage = 40 // ad-hoc background tasks (app.Go) )
Built-in stages, in shutdown order. Custom components may use any value; equal values stop together.
type State ¶
type State int
State is the lifecycle state of a supervised component.
const ( StatePending State = iota // registered, not started (not yet running, or its roles are not selected) StateStarting // goroutine launched StateRunning // inside Run StateBackoff // failed; waiting to restart StateDone // Run returned nil before shutdown StateFailed // failed and will not be restarted StateStopped // stopped by shutdown )
Component states, as reported by Supervisor.Status.
type Supervisor ¶
type Supervisor struct {
// contains filtered or unexported fields
}
Supervisor runs components as goroutines, restarts or escalates failures, and shuts everything down in stage order.
A Supervisor is safe for concurrent use. Components may be added before or during Run (for example, a background task started from a request handler).
func (*Supervisor) Add ¶
func (s *Supervisor) Add(spec Spec) error
Add registers a component. Names must be unique. If the supervisor is already running and the component's roles are selected, it starts immediately. Add returns ErrStopping once shutdown has begun, including when Run is returning because every component has finished.
func (*Supervisor) Declare ¶ added in v0.3.0
func (s *Supervisor) Declare(roles ...string)
Declare makes roles known before any component has them, so Run accepts them: a feature whose components come later (the scheduler once it has tasks) declares its role when it is set up, and a process started with that role runs whatever it has, possibly nothing.
func (*Supervisor) Ready ¶
func (s *Supervisor) Ready() bool
Ready reports whether the supervisor is running, not shutting down, and every started component implementing Readier is ready. A Readier component that is waiting to restart or has failed counts as not ready. Use Ready for readiness probes.
func (*Supervisor) Roles ¶
func (s *Supervisor) Roles() []string
Roles returns the sorted set of roles of the registered components and those declared with Supervisor.Declare.
func (*Supervisor) Run ¶
func (s *Supervisor) Run(ctx context.Context, roles ...string) error
Run starts the components selected by roles (all components if roles is empty; components without roles always run) and blocks until ctx is canceled, a StopOnFailure component fails, or every component has returned. It then shuts down stage by stage within Options.ShutdownTimeout.
Run returns nil after a clean shutdown, the failing component's error for an escalated failure, and an error wrapping ErrShutdownTimeout if components did not stop in time. Requesting a role that no component has and no one declared (Supervisor.Declare) is an error, which catches typos in --only flags.
Context values from ctx are visible to components; its cancellation only triggers shutdown, which the supervisor then performs in stage order.
func (*Supervisor) ShutdownDeadline ¶ added in v0.2.0
func (s *Supervisor) ShutdownDeadline() time.Time
ShutdownDeadline returns when the components' shutdown budget (Options.ShutdownTimeout) runs out, or the zero time if shutdown hasn't begun. Components that need time to stop, such as queue workers letting jobs finish, can plan with it.
func (*Supervisor) ShutdownStarted ¶
func (s *Supervisor) ShutdownStarted() time.Time
ShutdownStarted returns when shutdown began, or the zero time if it hasn't.
func (*Supervisor) Status ¶
func (s *Supervisor) Status() []ComponentStatus
Status returns a snapshot of every registered component, in registration order. It is intended for health endpoints, logs and CLI output.