reclaim

package
v1.0.0 Latest Latest
Warning

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

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

Documentation

Overview

Package reclaim deletes the on-disk caches an application leaves behind when it stops being reconciled: its clone under <data>/repos/<name> and its chart repository cache under <data>/charts/<name>.

Nothing else did. Reconciler.Remove drops the map entry, the credential and the order entry, and the two directories stay for ever — so app-of-apps churn, a preview environment per pull request being the obvious case, leaves one full clone plus one chart cache per application name *ever* declared. The data directory is a local volume on a manager node, sharing a filesystem with /var/lib/docker and the raft log, which is what makes filling it worse than it sounds: a git fetch that fails for every application is recoverable, and a raft log that can no longer be written is not.

Why this is a sweep and not part of Remove

A removal races an in-flight sync of the same application. Remove cancels that application's loop and waits for the goroutine, but a sync the API started runs on the request's context and is neither cancelled nor waited for (swarmcli-cd#106) — so at the moment Remove returns, something may still be reading the checkout. Deleting a working tree out from under a render does not fail cleanly; it renders half a repository and deploys the result.

So the decision is never taken at the moment of removal. A directory is deleted only once its name has been missing from the set for a whole sweep interval: the first sweep that misses it records it, only a later one removes it, and a name that comes back in between clears the record. That is what makes this safe while #106 is still open, rather than safe on the condition that it is fixed.

Why it needs no opt-in

Everything here is a cache. An application whose clone was reclaimed and that returns to the set is re-cloned on its first fetch and its chart repositories re-fetched, so the cost of being wrong is one slow reconcile. Package prune deletes what is deployed and is opt-in for exactly the reason this is not.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Options

type Options struct {
	// Roots are the directories holding one subdirectory per application. The
	// controller passes <data>/repos and <data>/charts; the app set's own clone
	// lives under neither, which is what keeps the bootstrap tier out of reach
	// of a sweep driven by the set it bootstraps.
	Roots []string
	Log   *slog.Logger
}

Options configures a Sweeper.

type Sweeper

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

Sweeper deletes the per-application directories under a set of roots.

Not safe for concurrent use, and it does not need to be: the app-set loop is its only caller and calls it from its own goroutine, on the same pass that decides which applications there are.

func New

func New(o Options) *Sweeper

New returns a Sweeper over roots.

func (*Sweeper) Sweep

func (s *Sweeper) Sweep(keep []string) error

Sweep deletes the directories under each root whose name is absent from keep, and was absent from it on the previous sweep too.

A root that does not exist yet is not an error: the controller creates both at startup, so an absent one is a run that has cached nothing under it.

Failures are collected rather than returned at the first, for the reason the prune sweep collects them: one directory that will not go is no reason to keep every later one. A failed removal stays a candidate, so the next sweep tries again immediately rather than starting its grace period over.

Jump to

Keyboard shortcuts

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