status

package
v0.16.0 Latest Latest
Warning

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

Go to latest
Published: Jul 31, 2026 License: Apache-2.0 Imports: 7 Imported by: 2

README

Status

The status package provides state management, progress reporting, and periodic task monitoring for Spirit migrations. It defines the lifecycle states that a migration passes through and the infrastructure for background checkpointing and status logging.

State Machine

State is an int32 enum representing the current phase of a migration. It uses atomic.LoadInt32/atomic.StoreInt32 for lock-free concurrent access, since the migration runner and watcher goroutines read and write the state simultaneously.

The states are defined in lifecycle order:

InitialCopyRowsWaitingOnSentinelTableApplyChangesetRestoreSecondaryIndexesAnalyzeTableChecksumPostChecksumCutOverReverseWindowCloseErrCleanup

This ordering is deliberate — the code uses ordinal comparisons (e.g., state >= CutOver) to determine when to stop checkpointing and status reporting.

ReverseWindow is entered only by a move run with --reverse-window set. It sorts immediately after CutOver: the forward cutover is done and traffic is on the target, but Spirit keeps the source current in change-only mode so the move can still be rolled back. Because it is >= CutOver, the background status/checkpoint loops have already stopped (the reverse-window driver manages its own checkpoint writes) while orchestration can still observe that a revert is possible.

Task Interface

The Task interface defines the contract that a migration runner must implement: reporting progress, returning a status string, dumping checkpoints, and cancelling. Both the migration.Runner and move.Runner implement this interface.

Background Monitoring

WatchTask launches two background goroutines:

  1. Status logger: Logs task.Status() every 30 seconds until the migration reaches cutover. This provides a regular heartbeat in the logs.
  2. Checkpoint dumper: Calls task.DumpCheckpoint() every 50 seconds until cutover. If a checkpoint write fails (with anything other than ErrWatermarkNotReady or context.Canceled), the task is cancelled immediately. The rationale is that it is better to fail early than to discover after a multi-day migration that progress was never being saved.

The checkpoint dumper also handles a race condition where the state transitions past cutover mid-checkpoint — the checkpoint table may have already been dropped, so this case is handled gracefully rather than treated as an error.

Progress Reporting

Progress is a struct (not just a string) containing the current state and a summary. It is designed as a struct specifically to allow future expansion for GUI wrappers and external tooling.

See Also

  • pkg/migration - Migration runner that implements the Task interface
  • pkg/move - Move runner that implements the Task interface

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrMismatchedAlter         = errors.New("alter statement in checkpoint table does not match the alter statement specified here")
	ErrBinlogNotFound          = errors.New("checkpoint binlog file not found on server")
	ErrCheckpointTooOld        = errors.New("checkpoint is too old to safely resume")
	ErrCheckpointCollision     = errors.New("checkpoint belongs to a different table (truncation collision)")
	ErrCouldNotWriteCheckpoint = errors.New("could not write checkpoint")
	ErrWatermarkNotReady       = errors.New("watermark not ready")
)
View Source
var (
	CheckpointDumpInterval = 50 * time.Second
	StatusInterval         = 30 * time.Second
)

Functions

func WatchTask

func WatchTask(ctx context.Context, task Task, logger *slog.Logger) (wait func())

WatchTask periodically does the status reporting for a task. This includes writing to the logger the current state, and dumping checkpoints.

It returns a wait function the caller can invoke during shutdown to block until the spawned goroutines have exited. This avoids races where a still-running checkpoint goroutine writes a fresh row after the caller has closed/torn down the surrounding state — a pattern that has produced flakes in tests that mutate the checkpoint table after Run() returns (see #773).

Types

type ChecksumProgress added in v0.16.0

type ChecksumProgress struct {
	RowsChecked uint64 // rows verified so far
	RowsTotal   uint64 // total rows to verify
}

ChecksumProgress tracks progress of the checksum phase, where Spirit verifies the copied data against the source before cutover. RowsChecked and RowsTotal are 0 outside the checksum phase.

func (ChecksumProgress) String added in v0.16.0

func (c ChecksumProgress) String() string

String renders the checksum progress for the human-readable summary line, e.g. "71436/221193 32.30%".

type ETA added in v0.16.0

type ETA struct {
	State    ETAState
	Duration time.Duration
}

ETA is the structured form of the ETA embedded in Summary. State reports whether Duration is available yet — e.g. ETAMeasuring during the initial window before a copy rate is known — so callers can show "calculating" rather than a misleading 0. Duration is the estimated remaining row-copy time, valid only when State is ETAReady and 0 otherwise.

type ETAState added in v0.16.0

type ETAState string

Progress is returned as a struct because we may add more to it later. It is designed for wrappers (like a GUI) to be able to summarize the current status without parsing log output. ETAState describes the availability of the row-copy ETA estimate, so callers can distinguish "still measuring" from a real estimate without parsing the Summary string. It mirrors the cases GetETA renders as text.

const (
	// ETANone means there is no copy ETA because the migration is not in the
	// row-copy phase. Duration is 0.
	ETANone ETAState = ""
	// ETAMeasuring means a copy is in progress but no copy rate has been measured
	// yet, so no estimate is available (Summary shows "ETA TBD"). Duration is 0.
	ETAMeasuring ETAState = "measuring"
	// ETAReady means Duration holds a current remaining-time estimate.
	ETAReady ETAState = "ready"
	// ETADue means the copy is essentially complete (Summary shows "ETA DUE").
	// Duration is 0.
	ETADue ETAState = "due"
)

type Progress

type Progress struct {
	CurrentState State  // current state, i.e. CopyRows
	Summary      string // text based representation, i.e. "12.5% copyRows ETA 1h 30m"

	// ETA is the structured remaining row-copy estimate and its availability.
	ETA ETA

	// Checksum is the structured progress of the post-copy checksum phase,
	// populated while CurrentState is Checksum and zero otherwise. It is the
	// structured form of the checksum progress embedded in Summary.
	Checksum ChecksumProgress

	// Tables contains per-table progress for multi-table migrations.
	// For single-table migrations, this will have one entry.
	Tables []TableProgress
}

type State

type State int32
const (
	Initial State = iota
	CopyRows
	ApplyChangeset // first mass apply
	RestoreSecondaryIndexes
	AnalyzeTable
	Checksum
	PostChecksum // second mass apply
	// WaitingOnSentinelTable comes after the initial checksum so that
	// `state >= Checksum` is true while the sentinel-wait blocks the cutover.
	// During this state Spirit also runs the "continuous checksum" loop
	// described in docs/migrate.md.
	WaitingOnSentinelTable
	CutOver
	// ReverseWindow is the post-cutover reverse window, entered only when
	// --reverse-window > 0: traffic is on the target and spirit keeps the source
	// current in change-only mode while watching for a revert request. It sorts
	// after CutOver (so `state >= Checksum` stays true) and lets orchestration
	// surface that a revert is still possible.
	ReverseWindow
	Close
	ErrCleanup
)

func (*State) Get

func (s *State) Get() State

func (*State) Set

func (s *State) Set(newState State)

func (State) String

func (s State) String() string

type TableProgress added in v0.11.0

type TableProgress struct {
	TableName  string // name of the table being migrated
	RowsCopied uint64 // rows copied so far
	RowsTotal  uint64 // total rows expected
	IsComplete bool   // true if this table's copy is complete
}

TableProgress tracks progress for a single table in the migration.

type Task

type Task interface {
	Progress() Progress
	Status() string // prints to logger, to return value
	DumpCheckpoint(ctx context.Context) error
	Cancel() // a callback to be able to cancel the task.
}

Jump to

Keyboard shortcuts

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