-
Notifications
You must be signed in to change notification settings - Fork 0
Maintenance
Silo runs its own housekeeping in-process — no separate cron container, no sidecar. Every replica runs the same jobs independently; each one recomputes its own next-fire time in memory, and every job is either idempotent (a delete another replica already made affects zero rows) or convergent (a metrics refresh), so there's no coordination between replicas and no downside to two of them firing the same job in the same minute.
Three jobs exist today: session_cleanup, audit_prune, and package_prune. Each has its own cron schedule in jobs:, 6 fields with seconds first (e.g. "0 */5 * * * *" for every 5 minutes):
jobs:
session_cleanup: "0 */5 * * * *" # default — purges expired login sessions
audit_prune: "0 0 * * * *" # default — enforces audit.retention_days
package_prune: "0 0 3 * * *" # no default — see belowsession_cleanup and audit_prune ship with defaults that match silo's historical cadence, so omitting jobs: entirely changes nothing. package_prune has no default: leaving it unset means package pruning never runs on a schedule, only when triggered by hand with silo prune.
Pruning deletes old package versions according to per-(repo, channel) retention rules. It's off by default at two levels:
prune:
enabled: false # global switch — must be true for *any* pruning to runWith prune.enabled: false, both the scheduled job and a manual silo prune refuse to run, even if rules are configured — flipping the global switch back off is enough to stop pruning without having to unwind every rule an admin set up.
A rule lives per (repo, channel) and is one or both of:
-
keep_last_n— keep only the N most recently published versions. -
max_age_days— delete anything published more than N days ago.
Both can be set at once. When they are, a version is pruned if it violates either one — the two conditions union rather than intersect. "Delete everything except the latest" is just keep_last_n=1.
Versions of the same package are grouped by (format, index_group, name) — the same identity the index renderer uses to tell one apk architecture's build of a package apart from another's, or one npm package from a same-named one in a different index group. keep_last_n counts within that group, not across the whole repo/channel.
silo repo set-prune-rule myrepo --channel stable --keep-last 10
silo repo set-prune-rule myrepo --channel stable --keep-last 10 --max-age-days 180
silo repo get-prune-rule myrepo --channel stable
silo repo set-prune-rule myrepo --channel stable --clearA (repo, channel) with no rule configured is simply skipped by both the scheduled job and silo prune — not an error, since most repos will never need one.
Exempting a package name protects every version of it, in that repo/channel, from both rules:
silo repo prune-exempt myrepo --channel stable --name curl
silo repo prune-exempt myrepo --channel stable --name curl --remove
silo repo list-prune-exemptions myrepo --channel stableUse this for a package that needs to keep old versions around indefinitely — a pinned dependency, a long-term-support build — without exempting the rest of the repo.
With prune.enabled: true and jobs.package_prune set, pruning runs on schedule with no further action. It can also be triggered by hand at any time, which is also how it's meant to be tested before relying on the schedule:
silo prune --repo myrepo --channel stable --dry-run # report only, deletes nothing
silo prune --repo myrepo --channel stable # prune that scope
silo prune # every configured rule, every repo--dry-run reports exactly what a live run would delete — grouped by repo, channel, package, and which rule(s) matched — without touching anything, and without writing to the audit log (nothing changed, so there's nothing to record). Omitting --repo runs every (repo, channel) that has a rule configured; a bare --channel without --repo is rejected, since a channel name alone doesn't identify a scope.
A live run reuses the same delete path a manual silo delete uses — storage delete, index regeneration, and one package.delete audit entry per package, now carrying {"reason": "prune", "rules": [...]} in its detail so a prune-triggered delete is distinguishable from a manual one without needing a separate action name. Each (repo, channel) a run actually deletes from also gets one repo.prune_run summary entry with the counts. See Usage for reading the audit log with silo audit.
See Setup for the full config.yaml schema this page's prune: and jobs: blocks belong to, and Usage for tokens, repo modes, and the rest of silo's admin commands.