supervisor

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Oct 8, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

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

Constants

This section is empty.

Variables

View Source
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.

func Func

func Func(name string, run func(ctx context.Context) error) Component

Func adapts a function to a Component.

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
)

func (Restart) String

func (r Restart) String() string

String returns the policy's name, as in logs.

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.

func (State) String

func (s State) String() string

String returns the state's name, as in logs and 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 New

func New(opts Options) *Supervisor

New returns a Supervisor with the given options.

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.

Jump to

Keyboard shortcuts

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