gscore

package
v0.9.1 Latest Latest
Warning

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

Go to latest
Published: Jun 30, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package gscore is the framework-agnostic engine behind the gsfiber (Fiber v2) and gsfiberv3 (Fiber v3) graceful-shutdown adapters. It orchestrates the shutdown lifecycle: signal capture, pre-stop delay, readiness flip, HTTP drain, ordered hooks, GORM pool close, and a force-kill ceiling.

The public adapter packages are thin wrappers that translate a framework's Shutdown method into the generic Shutdowner interface accepted here.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type CloserRegistrar added in v0.7.0

type CloserRegistrar interface {
	RegisterCloser(name string, phase int, timeout time.Duration, fn func(ctx context.Context) error)
	RegisterCloserWithPriority(name string, phase int, priority int, timeout time.Duration, fn func(ctx context.Context) error)
}

CloserRegistrar is the minimal interface that gscore.Manager satisfies for registering graceful-shutdown closers. Sub-packages (txcore, apmcore, logcore, gormautobatch, gsredis, gsrueidis) declare a local type alias to this interface to avoid importing gscore directly.

type Config

type Config struct {
	// Signals that trigger Start to return and shutdown to begin. Defaults
	// to SIGINT + SIGTERM when nil.
	Signals []os.Signal

	// PreStopDelay is a sleep injected after a signal is received but
	// before any phase runs. Gives kube-proxy / load balancers time to
	// observe the failing readiness probe and stop routing new traffic.
	// Zero disables the delay.
	PreStopDelay time.Duration

	// Per-phase timeouts. Zero means "use ForceKillAfter as a soft cap"
	// (i.e. no per-phase deadline beyond the global one).
	DrainTimeout   time.Duration
	HookTimeout    time.Duration // applied per phase, not per hook
	DBCloseTimeout time.Duration

	// ForceKillAfter bounds the whole shutdown sequence. When exceeded,
	// the Manager logs an error and calls os.Exit(1). Zero disables.
	ForceKillAfter time.Duration

	// Logger receives per-phase events. Nil = silent.
	Logger Logger

	// OnHookError is invoked whenever a hook returns a non-nil error.
	// It does not stop the sequence. Nil = errors only go to the logger.
	OnHookError func(name string, phase Phase, err error)
}

Config configures a Manager. All durations are independent; the global ForceKillAfter bounds the entire sequence as a hard ceiling.

func (Config) WithDefaults

func (cfg Config) WithDefaults() Config

WithDefaults returns cfg with zero-valued fields filled in.

type Hook

type Hook struct {
	Name     string
	Priority int
	Phase    Phase
	Run      func(ctx context.Context) error
}

Hook is a user-registered shutdown action. Lower Priority runs first within the same phase; equal priorities run in registration order.

type Logger

type Logger interface {
	Info(msg string, kv ...any)
	Warn(msg string, kv ...any)
	Error(msg string, kv ...any)
}

Logger is the structured-logging surface the Manager calls during the shutdown sequence. Implementations should be safe for concurrent use.

type Manager

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

Manager coordinates the shutdown sequence. It is safe to construct once at boot and share across goroutines; Trigger and Wait may be called concurrently.

func New

func New(cfg Config) *Manager

New constructs a Manager. The returned Manager's RootContext is live until Trigger fires.

func (*Manager) AddHook

func (m *Manager) AddHook(h Hook)

AddHook registers a hook to run during phase h.Phase.

func (*Manager) IsReady

func (m *Manager) IsReady() bool

IsReady reports the readiness flag. It is true at construction and flipped to false the moment a shutdown signal is observed. Kubernetes readiness probes should reflect this value.

func (*Manager) IsStarted added in v0.7.1

func (m *Manager) IsStarted() bool

IsStarted reports whether MarkStarted has been called. Kubernetes startup probes should reflect this value: while false the pod is still initializing and liveness/readiness probes are suspended by Kubernetes.

func (*Manager) ListenAndWait

func (m *Manager) ListenAndWait() error

ListenAndWait blocks until one of cfg.Signals is received OR Trigger is called from elsewhere, then runs the shutdown sequence and returns. Typical use is `defer mgr.ListenAndWait()` at the end of main, after starting the server in a goroutine.

func (*Manager) MarkStarted added in v0.7.1

func (m *Manager) MarkStarted()

MarkStarted signals that the application has finished initializing (migrations ran, caches warmed up, etc.) and is ready to serve traffic. Call this once at the end of your boot sequence, before blocking on ListenAndWait. It also records the current wall-clock time so that StartedAt can report the exact moment the startup probe flipped to 200.

func (*Manager) RegisterCloser

func (m *Manager) RegisterCloser(name string, phase int, timeout time.Duration, fn func(ctx context.Context) error)

RegisterCloser registers a generic resource close action for the given phase. Closers run sequentially within the phase (after that phase's hooks), each bounded by its own timeout — so a slow Redis client cannot starve a fast Kafka producer that comes after it.

Typical placements:

  • PhasePostDrain: outbound clients that the handler chain used (HTTP clients, gRPC connections) and that the DB close does not depend on.
  • PhasePostDB: Redis / cache / search clients consumed during DB commit-time callbacks (e.g. txctx.OnCommit). Closing them only after PhaseDB guarantees those callbacks completed.

timeout=0 falls back to Config.HookTimeout. Empty name is auto-filled. A nil fn is a no-op (the entry is dropped).

phase accepts int so that sub-packages (txcore, apmcore, logcore, gormautobatch) can satisfy the CloserRegistrar interface without importing gscore. Pass the Phase constants as int: int(gscore.PhasePostDrain). For typed usage call RegisterCloserAt instead.

func (*Manager) RegisterCloserAt added in v0.7.0

func (m *Manager) RegisterCloserAt(name string, phase Phase, timeout time.Duration, fn func(ctx context.Context) error)

RegisterCloserAt is like RegisterCloser but accepts the typed Phase constant directly, which is more ergonomic when calling from within the gscore package or from packages that import gscore explicitly.

func (*Manager) RegisterCloserWithPriority added in v0.7.0

func (m *Manager) RegisterCloserWithPriority(name string, phase int, priority int, timeout time.Duration, fn func(ctx context.Context) error)

RegisterCloserWithPriority is like RegisterCloser but also sets a priority. Within the same phase, closers with lower priority values run first; closers with equal priorities run in registration order. RegisterCloser uses priority 0.

func (*Manager) RegisterCloserWithPriorityAt added in v0.7.0

func (m *Manager) RegisterCloserWithPriorityAt(name string, phase Phase, priority int, timeout time.Duration, fn func(ctx context.Context) error)

RegisterCloserWithPriorityAt is like RegisterCloserWithPriority but accepts the typed Phase constant directly.

func (*Manager) RegisterDB

func (m *Manager) RegisterDB(db *gorm.DB)

RegisterDB adds a GORM DB whose underlying *sql.DB will be Close()'d during PhaseDB. Multiple DBs are closed sequentially in registration order.

func (*Manager) RegisterServer

func (m *Manager) RegisterServer(s Shutdowner)

RegisterServer adds an HTTP-like server to be drained during PhaseDrain. Multiple servers are drained concurrently with a shared deadline.

func (*Manager) RootContext

func (m *Manager) RootContext() context.Context

RootContext returns a context.Context that is cancelled the moment the shutdown sequence begins. Outbound HTTP clients, workers, and any long-running operation should derive their context from this so they observe shutdown via ctx.Done().

func (*Manager) SetReady

func (m *Manager) SetReady(v bool)

SetReady forces the readiness flag. Useful for tests or for marking "not ready" before the process is even started.

func (*Manager) StartedAt added in v0.8.3

func (m *Manager) StartedAt() time.Time

StartedAt returns the wall-clock time at which MarkStarted was called. It returns the zero time if MarkStarted has not been called yet.

func (*Manager) Trigger

func (m *Manager) Trigger()

Trigger initiates the shutdown sequence programmatically (e.g. from a health-check failure or an unrecoverable error). Subsequent calls are no-ops. It returns immediately; callers should Wait for completion.

func (*Manager) Wait

func (m *Manager) Wait() error

Wait blocks until the shutdown sequence has finished (or os.Exit was invoked by the force-kill ceiling). The returned error is the first fatal error encountered, or nil on a clean shutdown.

type Phase

type Phase int

Phase identifies a stage of the shutdown sequence. Hooks are grouped by phase; phases run sequentially in the order below.

const (
	// PhasePreStop runs first, before HTTP drain. Use it for actions that
	// must happen while the server is still serving (e.g. flushing an
	// in-memory queue back to a durable store).
	PhasePreStop Phase = iota
	// PhaseDrain runs the HTTP server drain.
	PhaseDrain
	// PhasePostDrain runs after the HTTP server is fully drained but before
	// the database pool is closed. Most outbound-call cleanups belong here.
	PhasePostDrain
	// PhaseDB runs the GORM pool close.
	PhaseDB
	// PhasePostDB runs last, after the database is closed. Use it for
	// resources that do not depend on the DB (Kafka producers, log
	// flushers, metric exporters).
	PhasePostDB
)

func (Phase) String

func (p Phase) String() string

type Shutdowner

type Shutdowner interface {
	// ShutdownWithContext must stop accepting new connections and wait for
	// in-flight requests to finish, returning when ctx is done or all
	// requests drained.
	ShutdownWithContext(ctx context.Context) error
}

Shutdowner is the minimal contract an HTTP server (or anything similar) must satisfy to be drained by the Manager. Both Fiber v2 (*fiber.App) and Fiber v3 (*fiber.App) implement Shutdown / ShutdownWithContext directly; the adapter packages adapt the exact signature.

Jump to

Keyboard shortcuts

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