lifecycle

package
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Nov 7, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package lifecycle gives a module three moments — init, ready, shutdown — and the signal handling that makes shutdown actually happen.

The ordering rule is the whole point. Hooks run in registration order going up and in REVERSE registration order coming down, so a module can safely assume that anything it was wired after is still alive while it drains.

Index

Constants

View Source
const DefaultDrainTimeout = 25 * time.Second

DefaultDrainTimeout is how long Run waits for in-flight work after a signal.

Variables

Signals are the signals Run treats as "shut down cleanly".

Functions

func Run

func Run(ctx context.Context, r *Registry, serve func() error, stop func(context.Context) error, drain time.Duration) error

Run is the standard main loop: initialise, serve, wait for a signal, drain.

  • serve blocks until the listener stops. A nil return means an intentional stop; an error means the listener died and the process should exit non-zero.
  • stop is called once a signal arrives, and must make serve return.

The drain context is a FRESH one with its own deadline, not a child of the cancelled parent. Deriving it from the cancelled context is the classic bug: every shutdown hook gets a context that is already done and skips its work.

Types

type Hook

type Hook struct {
	Name     string
	Init     func(ctx context.Context) error
	Ready    func(ctx context.Context) error
	Shutdown func(ctx context.Context) error
	Reload   func(ctx context.Context) error
}

Hook is one named participant in the lifecycle. A hook need only implement the phases it cares about.

type Initializer

type Initializer interface {
	OnInit(ctx context.Context) error
}

Initializer runs after the container is wired and before the server accepts traffic. Open pools, warm caches, verify a dependency answers.

An error here fails the boot. That is intended: a service that cannot reach its database should not report healthy and serve 500s.

type Ready

type Ready interface {
	OnReady(ctx context.Context) error
}

Ready runs after the listener is up. Start background loops here, not in OnInit — a reconciler that begins before the process is serving will race the boot it is part of.

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry collects hooks and runs each phase in the right order.

The zero value is ready to use.

func (*Registry) Add

func (r *Registry) Add(h Hook)

Add registers a hook. Order matters: later hooks initialise after earlier ones and shut down before them.

func (*Registry) AddReload added in v1.1.0

func (r *Registry) AddReload(name string, fn func(context.Context) error)

AddReload registers a named reload callback without making it a lifecycle participant. This is useful for configuration loaders that do not own a resource to initialise or shut down.

func (*Registry) Init

func (r *Registry) Init(ctx context.Context) error

Init runs every Init hook in registration order and STOPS at the first failure, returning it.

It stops rather than continuing because the hooks after a failed one were written assuming it succeeded. Whatever did initialise is recorded, so a following Shutdown unwinds exactly that much and no more.

func (*Registry) Names

func (r *Registry) Names() []string

Names lists registered hooks in order.

func (*Registry) Observe

func (r *Registry) Observe(name string, v any)

Observe registers whichever lifecycle interfaces v implements. Pass a module or a provider and the registry works out what it participates in; passing something that implements none is a no-op, not an error.

func (*Registry) Ready

func (r *Registry) Ready(ctx context.Context) error

Ready runs every Ready hook in registration order. Unlike Init it runs them ALL and joins the errors: the process is already serving, and refusing to start a second background loop because the first one stuttered helps nobody.

func (*Registry) Reload added in v1.1.0

func (r *Registry) Reload(ctx context.Context) error

Reload runs all registered reload callbacks in registration order. A bad callback does not prevent independent configuration sections from trying to refresh; callers receive the joined errors and keep the old configuration.

func (*Registry) Shutdown

func (r *Registry) Shutdown(ctx context.Context) error

Shutdown runs the Shutdown hook of everything that initialised, in reverse order, and joins the errors — one slow client must not keep the rest from draining.

type Reloader added in v1.1.0

type Reloader interface {
	OnReload(ctx context.Context) error
}

Reloader refreshes runtime configuration after SIGHUP or an explicit Application.Reload call. Reload failures are reported and the process keeps serving with the last known-good configuration.

type Shutdowner

type Shutdowner interface {
	OnShutdown(ctx context.Context) error
}

Shutdowner runs on the way down, in reverse registration order, under the drain deadline. Stop loops, flush buffers, close clients.

Jump to

Keyboard shortcuts

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