Skip to content

Daily cron: sweep expired preview artifacts from R2#45

Merged
fengmk2 merged 2 commits into
mainfrom
cron-cleanup-expired
Jul 1, 2026
Merged

Daily cron: sweep expired preview artifacts from R2#45
fengmk2 merged 2 commits into
mainfrom
cron-cleanup-expired

Conversation

@fengmk2

@fengmk2 fengmk2 commented Jul 1, 2026

Copy link
Copy Markdown
Member

Adds the scheduled cleanup you asked for.

Why

Refs self-expire from the indexes (skipped on read, pruned on the next write), but their per-version R2 objects , meta/<name>/<version>.json and the tarball , were only ever deleted on explicit /-/purge. So R2 storage grew with every ref ever published, unbounded under continuous releases.

What

  • cleanupExpiredArtifacts (src/preview/cleanupExpired.ts): lists the meta/ and tarball/ prefixes and bulk-deletes objects whose uploaded age exceeds REF_TTL_MS. Since a ref's objects are re-uploaded on each publish, uploaded age tracks the ref's age and the cutoff maps exactly to the ref TTL , an active ref is never touched, and the live indexes (refs/, meta-index/) sit under different prefixes and are left alone.
  • crons/cleanup-expired.ts: a Void cron (export const cron = '37 3 * * *', daily) that runs it. Confirmed viable , .void/entry.ts already exports { fetch, scheduled } and dispatches cron jobs, so this composes with the routes/ app entry; no external scheduler.

Verify

tsc clean (added crons to the tsconfig include), 77 tests pass , new tests confirm it deletes past-TTL objects, keeps in-TTL ones, and never touches the refs//meta-index/ objects. Bundle unaffected. The staging deploy will exercise the cron-trigger provisioning on the real Void runtime.

fengmk2 added 2 commits July 1, 2026 13:03
Refs self-expire from the indexes (skipped on read, pruned on the next write),
but their per-version R2 objects (meta/<name>/<version>.json and the tarball)
were never auto-deleted, only on explicit purge, so R2 storage grew with every
ref ever published.

Add cleanupExpiredArtifacts: it lists the meta/ and tarball/ prefixes and
bulk-deletes objects whose uploaded age exceeds REF_TTL_MS. Each object is
re-uploaded on republish, so uploaded age tracks the ref's age and the cutoff
maps exactly to the ref TTL, an active ref is never touched, and the live indexes
(refs/, meta-index/) are under different prefixes and left alone. A Void cron
(crons/cleanup-expired.ts, daily) runs it; the generated Worker already dispatches
scheduled events, so this composes with the routes/ app entry.
The expiry sweep hardcoded ['meta/', 'tarball/'] kept in sync with metaKey/
tarballKey only by a 'must match' comment; a prefix rename would silently desync
the cron (it would stop matching and R2 would leak with no error). Export the two
prefixes from r2Cache, use them in both the key builders and the sweep.
@fengmk2 fengmk2 force-pushed the cron-cleanup-expired branch from 2495fdd to 3dfe6d5 Compare July 1, 2026 05:04
@fengmk2 fengmk2 merged commit d580a26 into main Jul 1, 2026
4 checks passed
@fengmk2 fengmk2 deleted the cron-cleanup-expired branch July 1, 2026 05:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant