Documentation
¶
Overview ¶
Package sagagc periodically drives saga retention, deleting executions that have been in a terminal state longer than the retention window.
Saga executions are durable by design: the executor persists one on every state transition so a crashed process can resume or roll back. Nothing ever removed them, so a cluster accumulated one entity per sandbox creation and per build forever, each carrying a JSON blob of every action's output. Garden reached roughly 4,900 in a month of gentle use, and a single app that fails to bind its declared port retries on a loop and writes thousands a day (MIR-1519).
The same tick also drives the stalled-saga sweep, which handles the executions retention cannot: ones still in flight that nothing will ever resume, so nothing will ever move them into a state retention collects (MIR-1788).
The policy itself lives in pkg/saga, which owns how executions are stored. This package is the schedule: when to sweep, how much to do at once, and what to tell an operator afterwards.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type GCConfig ¶
type GCConfig struct {
// Retention is how long a terminal execution is kept after it finished.
// Zero disables deletion entirely.
Retention time.Duration
// CheckInterval is how often to run a sweep.
CheckInterval time.Duration
// MaxDeletesPerSweep caps deletions per sweep so an accumulated backlog
// drains over several passes. Zero means unbounded.
MaxDeletesPerSweep int
// SweepTimeout bounds a single sweep. A truncated sweep is fine; the next
// one picks up where this left off, since the pass is idempotent.
SweepTimeout time.Duration
// StaleAfter is how long an in-flight execution may sit without changing
// state before it is declared stranded and forced to failed. Zero disables
// the stalled sweep. No config field sets this directly; see
// EntityMaintenance for why saga.retention_period drives both windows.
StaleAfter time.Duration
// MaxForcesPerSweep caps stalled transitions per sweep, on the same
// reasoning as MaxDeletesPerSweep. Zero means unbounded.
MaxForcesPerSweep int
}
GCConfig tunes the retention sweep.
func DefaultGCConfig ¶
func DefaultGCConfig() GCConfig
DefaultGCConfig returns the default configuration. The seven-day retention is what RFD-35 committed to. The per-sweep cap and interval together drain about 48,000 executions a day, comfortably ahead of the worst observed write rate.
StaleAfter reuses the same seven days, which is generous against what it measures: the gap between two steps of a saga, not the life of one. A forced execution then waits out Retention, so a stranded record takes about a fortnight to go entirely, and an operator has a week to see what was forced.
type GCController ¶
type GCController struct {
Log *slog.Logger
Storage Storage
Config GCConfig
// contains filtered or unexported fields
}
GCController periodically deletes expired saga executions and forces stranded ones. It runs on the coordinator, so exactly one process is sweeping and it never contends with runners writing saga state through the entity-access client.
func (*GCController) Start ¶
func (c *GCController) Start(ctx context.Context)
Start begins the periodic sweep.
Zeroing a window disables that sweep, and there is only a controller to run at all if at least one of them is on. An operator reaches this through one config field that zeroes both together; the gate reads them separately because a caller that wires only one of them is still a caller worth serving, and because reading Retention alone here would silently take the stalled sweep down with it.
type Storage ¶ added in v0.15.0
type Storage interface {
saga.Storage
saga.StalledStorage
}
Storage is what this controller needs to sweep: retention's view plus the conditional transition the stalled sweep writes through.
Only the direct entity-store backend satisfies both, which is the point. The controller was always coordinator-only, stated in a comment; requiring the narrower interface makes an entity-access-backed storage fail to compile here rather than fail to be safe at runtime.