feat: background syncer for github_rpm remotes #108
Reference in New Issue
Block a user
Delete Branch "benvin/github-rpm-syncer"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Why
Builds on #107 (merged), which derives
github_rpmRPM metadata lazily on theclient request path, single-flighted per replica. Two problems remain: the
derive still happens per replica, so across a multi-replica deployment the same
releases are scanned and re-derived N times, multiplying GitHub queries; and a
cold cache blocks the first request on a full derive. GitHub's rate limits are
low (~60/hr unauthenticated, ~5000/hr authenticated), so this needs a single
coordinated syncer with a shared rate limit and conditional requests.
How
on shutdown) that owns a deduped/coalescing work queue, a worker pool, and one
global token-bucket rate limiter (
golang.org/x/time/rate) bound onto thegithub provider so every GitHub call (releases list + each ranged asset GET)
acquires a token first.
github_rpmremote for new/changed releases on its existingmutable_ttlcadence; derive only new/changed assets incrementally and pruneassets that disappear upstream. Repodata is served from primed DB rows.
immediately.
ETagasIf-None-Match; a304derivesnothing and is not counted against GitHub's rate limit, so an unchanged repo
is nearly free.
github_rpm_sync_staterow (last_synced_at,etag,sync_lease_owner,sync_lease_expires): a periodic scan runs onlyfor the replica that atomically claims the lease, bounding total GitHub load
to ~once per
mutable_ttlregardless of replica count; the ETag is sharedthrough the same row.
cache, and return a bounded wait then a retryable
503rather than blockingon a cold derive.
GITHUB_SYNC_RATE/GITHUB_SYNC_BURST/GITHUB_SYNC_WORKERS/GITHUB_SYNC_POLL_INTERVALconfig with conservative defaults (1 req/s, burst5, 3 workers, 60s tick) and document the syncer in the README.
Tests
304releases response derivesnothing; incremental derive fetches only the newly added asset; the shared
limiter caps request rate; work-queue enqueues coalesce to one job; prime
enqueues a job; a held lease stops a second replica from scanning; cold-start
serves
503while warm cache serves200.time, recency gate blocks a too-soon periodic re-claim, prime (freshness 0)
bypasses recency but respects a live lease.
dnf install dotvaultworks; prime-on-create derives in thebackground at ~1 req/s (global limiter);
dnf makecacheserved fast from thepriming cache (no cold block); clean shutdown mid-scan, no panics.
Notes
mutable_ttlas the check interval (no new per-remote field), per brief.