safemode

package
v0.9.2 Latest Latest
Warning

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

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

Documentation

Overview

Package safemode keeps a boot ledger so a control plane that cannot start stops restarting and serves a read-only recovery page instead.

Index

Constants

View Source
const (
	EnvAfterFailures = "APP_SAFE_MODE_AFTER_FAILURES"
	EnvBackoffBase   = "APP_BOOT_BACKOFF_BASE"
	EnvBackoffMax    = "APP_BOOT_BACKOFF_MAX"
	EnvHealthyAfter  = "APP_BOOT_HEALTHY_AFTER"
)

Environment variables that tune boot failure handling.

View Source
const (
	ReasonDBCorrupt       = "db_corrupt"
	ReasonMigrationFailed = "migration_failed"
	ReasonStoreFailed     = "store_open_failed"
	ReasonCrashLoop       = "crash_loop"
)

Reasons the control plane enters safe mode.

View Source
const (
	ActionRestore = "restore"
	ActionRetry   = "retry"
)

Recovery actions.

View Source
const LedgerFilename = "boot-ledger.json"

LedgerFilename is the boot ledger under the data dir.

View Source
const TokenFilename = "safe-mode-token"

TokenFilename holds the one-time code that unlocks recovery. Reading it needs host access.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	DataDir string
	Brand   string
	Version string
	Entry   Entry
	Backups integrity.BackupLister
	Ledger  *Ledger
	// Restart asks the process to exit so its supervisor relaunches it.
	Restart func()
	Logger  *slog.Logger
	Now     func() time.Time
}

Config wires the recovery page to the process.

type Entry

type Entry struct {
	Reason   string
	Detail   string
	Failures int
}

Entry says why safe mode started.

type Ledger

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

Ledger counts consecutive boots that never became healthy.

func NewLedger

func NewLedger(dataDir string) *Ledger

NewLedger returns a ledger stored under dataDir.

func (*Ledger) Begin

func (l *Ledger) Begin() State

Begin records a start. A previous start that never reached MarkHealthy or MarkClean counts as one more failure.

func (*Ledger) ExitSafeMode

func (l *Ledger) ExitSafeMode(threshold int)

ExitSafeMode records that safe mode ended without a recovery action. The next boot gets exactly one more attempt, so a manual restart after fixing the cause works and a broken install lands back in safe mode.

func (*Ledger) MarkClean

func (l *Ledger) MarkClean()

MarkClean records a deliberate stop so it is not counted as a crash.

func (*Ledger) MarkHealthy

func (l *Ledger) MarkHealthy()

MarkHealthy records that this boot stayed up, which clears the failure count.

func (*Ledger) NoteError

func (l *Ledger) NoteError(err error)

NoteError remembers why the last boot failed.

func (*Ledger) Reset

func (l *Ledger) Reset()

Reset forgets every failure, for a manual recovery.

type Policy

type Policy struct {
	Threshold    int
	BackoffBase  time.Duration
	BackoffMax   time.Duration
	HealthyAfter time.Duration
}

Policy turns a failure count into a delay and a safe mode decision.

func PolicyFromEnv

func PolicyFromEnv(getenv func(string) string) Policy

PolicyFromEnv reads the APP_SAFE_MODE_* and APP_BOOT_* overrides.

func (Policy) Backoff

func (p Policy) Backoff(failures int) time.Duration

Backoff is how long to wait before this boot continues: zero for a clean history, then exponential up to BackoffMax.

func (Policy) SafeMode

func (p Policy) SafeMode(failures int) bool

SafeMode reports whether failures have reached the point where restarting again is pointless.

type Server

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

Server is the read-only recovery surface served instead of the dashboard.

func New

func New(cfg Config) (*Server, error)

New creates the server and writes a fresh recovery code to the data dir.

func (*Server) Handler

func (s *Server) Handler() http.Handler

Handler serves the recovery page and its small API.

func (*Server) Serve

func (s *Server) Serve(ctx context.Context, addr string) error

Serve runs the recovery server on addr until ctx ends.

func (*Server) Token

func (s *Server) Token() string

Token returns the recovery code, for tests.

type State

type State struct {
	Failures  int       `json:"failures"`
	Healthy   bool      `json:"healthy"`
	LastStart time.Time `json:"last_start"`
	LastError string    `json:"last_error,omitempty"`
}

State is what the ledger remembers between boots.

Jump to

Keyboard shortcuts

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