Skip to content

Refresh the most used packages in the background - #645

Open
simonchrz wants to merge 6 commits into
git-pkgs:mainfrom
simonchrz:feat/mirror-refresh
Open

simonchrz wants to merge 6 commits into
git-pkgs:mainfrom
simonchrz:feat/mirror-refresh

Conversation

@simonchrz

@simonchrz simonchrz commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Closes #632.

Adds mirror.refresh, a background job that mirrors new releases of the packages clients download most, so they are cached before the first install asks for them.

mirror:
  refresh:
    interval: 24h
    top: 50          # packages per ecosystem, by downloads within since
    since: 14d
    max_versions: 200
    max_bytes: 2GB

How the open questions from the issue are answered:

  • Which versions: the newest release of each major line a version is cached on (0.minor below 1.0). Prereleases, yanked releases, releases within cooldown and denied ones are skipped, so a run mirrors what clients would be served. A release that leaves cooldown later is picked up by a later run.
  • Which files: PyPI and conda get only the kinds of files clients fetched before: the same wheel tags or sdist, or the same conda subdir, build variant (py312) and type.
  • Storage: max_versions and max_bytes cap one run. Mirrored files are evicted by max_size and retention like any other.
  • Debian, Alpine, RPM: included. Their cache keys are hashed, so metadata_cache now records the upstream URL (migration 020). A run fetches the InRelease, APKINDEX.tar.gz and repomd.xml files clients fetched again, reads the Packages or primary index for the repositories and architectures of the cached packages, and mirrors the newest file an index lists per package and architecture when it isn't cached but an older version is, checked against the index's SHA-256. Suites sharing a pool, such as bookworm and trixie, are refreshed each on its own that way.
  • Several instances: the refresh runs through the schedule loop, so it claims its run in job_runs like schedules.
  • Images: not part of the refresh; mirror.schedules already covers tags. Julia (cached by tree hash), Arch and FreeBSD are left out too.

Tested end to end against the real upstreams: after a client fetched lodash 4.17.20, requests 2.31.0 (one wheel), curl from bookworm with the trixie InRelease, and docker-ce-cli 28.0.4 from download.docker.com, one run mirrored lodash 4.18.1, the matching requests 2.34.2 wheel only, curl 8.14.1-2+deb13u5 and docker-ce-cli 28.1.1. The next run had nothing to do, and the new files were served from the cache.

Migration 020 collides with #622 and #626; whichever lands later gets renumbered.

mirror.refresh mirrors, for the top packages per ecosystem by recent
downloads, the newest release of each major line a version is cached on.
Releases within cooldown or on the denylist are skipped, and PyPI and conda
get only the kinds of files clients fetched before. max_versions and
max_bytes cap one run. Instances sharing a database take turns as for
schedules.
The refresh fetches Debian, Alpine and RPM indexes again from the URLs
clients fetched them from, which the hashed cache keys don't keep. Rows
cached before get their URL on the next revalidation, even on a 304.
These clients find new versions in a repository index. The refresh fetches
the InRelease, APKINDEX and repomd.xml files clients fetched again, reads
the Packages and primary indexes they point at for the repositories the
most used packages came from, and mirrors the newer file per package and
architecture, checked against the index's SHA-256 where it has one.
An index file was mirrored only when it was newer than every cached
version of the package and architecture. Debian suites share one pool, so
once curl from trixie was cached, bookworm's security updates to curl
were older than it and never mirrored. A run now mirrors the newest file
an index lists when it isn't cached and an older version is, which still
never downgrades and leaves a suite alone that only has a newer version
cached.

Tests also cover repositories listing several versions, an unreadable
index next to working ones, Architecture: all packages, scoped npm
packages, denied releases, a listing failure next to other packages, a
cancelled run and Go version lines.
@simonchrz

Copy link
Copy Markdown
Contributor Author

Fixed in b73980e: Debian suites share one pool, so once curl from trixie was cached, bookworm's updates to curl were older than every cached version and never mirrored. A run now mirrors the newest file an index lists when it isn't cached but an older version is, so it still never downgrades. Also added tests for repositories listing several versions, an unreadable index, Architecture: all, scoped npm packages, denied releases, a cancelled run and Go version lines.

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.

Keep frequently used packages up to date in the background

1 participant

⌂ Proxy