gc

package
v0.30.38 Latest Latest
Warning

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

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

Documentation

Overview

Package gc provides a generic background sweep worker used by all GC subsystems in xolu: blob storage, timeseries retention, FSM machine collection (v2), and event delivery log cleanup (v2).

The package implements the ticker-and-stop-channel lifecycle pattern once so that each sweeper only needs to implement the Sweeper interface. Workers are registered at server startup and exposed via the admin API at POST /api/v1/admin/gc/{name}/run and GET /api/v1/admin/gc.

A panic in any registered Sweeper's own Sweep method is recovered by Worker.RunOnce, logged at Error level with a stack trace, and turned into a normal error -- one GC subsystem's bug degrades to a logged failure for that subsystem's own sweeps, never a crash of the whole server. See RunOnce's own doc comment for why this exists.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Report

type Report struct {
	Examined    int           // items inspected this cycle
	Collected   int           // items collected (deleted or hard-purged)
	Quarantined int           // items moved to a staging area (two-phase sweepers)
	Errors      int           // non-fatal errors encountered
	Duration    time.Duration // wall time for the sweep
}

Report summarises the result of a single sweep cycle. Zero values are valid; sweepers that do not track a field leave it at 0.

type Sweeper

type Sweeper interface {
	Sweep(ctx context.Context) (Report, error)
}

Sweeper is implemented by each GC subsystem. Sweep must be safe to call concurrently from RunOnce and the ticker goroutine.

type Worker

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

Worker runs a Sweeper on a ticker interval. It is safe for concurrent use.

func NewWorker

func NewWorker(name string, s Sweeper, interval time.Duration, logger zerolog.Logger) *Worker

NewWorker creates a Worker. Start must be called separately.

func (*Worker) LastReport

func (w *Worker) LastReport() (Report, time.Time)

LastReport returns the report from the most recent completed sweep and the time it started. Returns a zero Report and zero time if no sweep has completed yet.

func (*Worker) Name

func (w *Worker) Name() string

Name returns the worker's registered name.

func (*Worker) RunOnce

func (w *Worker) RunOnce(ctx context.Context) (r Report, err error)

RunOnce executes a single sweep synchronously. Used by the admin endpoint and by tests. Safe to call concurrently with the background goroutine.

Recovers a panic from the underlying Sweeper's own Sweep method, logs it at Error level with a full stack trace, and returns it as a normal error instead of letting it propagate -- added 2026-08-04 (T-156: a real type-assertion panic in pkg/timeseries's RetentionWorker, registered as exactly this kind of Sweeper, crashed CI outright). A server should never go down because one GC subsystem has a bug; the worker survives a panicking sweep and keeps ticking on schedule, the same way it already survives a sweep that returns a normal error.

func (*Worker) Start

func (w *Worker) Start()

Start launches the background sweep goroutine. Calling Start more than once on the same Worker panics.

The panic was always this method's documented contract, but the guard itself was never implemented: a second Start silently launched a second run() goroutine, and the eventual symptom was a "close of closed channel" panic in run()'s own deferred close(w.done) -- in a background goroutine, crashing the whole process, far from the call that caused it (demonstrated live by TestWorker_StartTwicePanics's own pre-fix run, which took down the test binary mid-suite attributed to a different test's name). Same lifecycle-unsafety family as pkg/server's own pre-T-140 Start/Shutdown race.

func (*Worker) Stop

func (w *Worker) Stop()

Stop signals the worker to stop and blocks until the background goroutine has exited. Idempotent. Calling Stop on a worker that was never started returns immediately -- there is nothing to wait for.

The previous behaviour, documented and implemented, was to block forever on <-w.done in that case: the same sharp edge as pkg/server's own pre-T-140 Shutdown-before-Start, kept alive here purely by its documentation. Not a live bug on any known call path (every worker the server registers is Started at registration, checked directly), but a footgun with no upside. A Start after such a Stop launches a goroutine that observes the already-closed stop channel and exits at once -- harmless by construction.

Jump to

Keyboard shortcuts

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