Repository navigation
fix(remote-cache): wait out the Registry's request limits and honour its 100 MiB artifact cap - #950
Open
tolgaergin wants to merge 9 commits into
Open
tolgaergin wants to merge 9 commits into
tolgaergin wants to merge 9 commits into
Conversation
…MiB artifact cap The LPM.dev Registry now limits remote cache uploads and cache hits per account and answers a request past a limit with 429. After a 429 the CLI skips that kind of request, lookups or uploads, for the rest of the run instead of sending more the limit would refuse, and warns once with the Registry's message. Tasks build as they would without a remote cache. The Registry stores artifacts up to 100 MiB, so the CLI skips uploading, and treats as a miss, anything larger. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…he run A 429 now pauses only its kind of request, lookups or uploads, until the time Retry-After gives (the header in seconds or as a date, else the body's retryAfter, else a minute; between a second and a day). The CLI then uses the remote cache again. Pauses are kept per cache server and team for the run, since each task builds its own client. A lookup limit pauses uploads too: a task that skipped its lookup would likely upload an artifact the cache already holds. Each kind of limit warns once on its own, so an earlier remote cache warning no longer hides it, and the warning says how long the CLI skips that kind of request. `lpm cache status` reports a 429 as the limit and when to try again. The 100 MiB artifact cap applies only to the LPM.dev Registry; other cache servers keep 500 MiB. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s in MiB An upload refused with a short Retry-After (5 s at most), as the Registry answers when the account has as many uploads in flight as it may or another upload holds its cache, now waits and goes once more instead of being dropped and pausing other uploads. A longer wait is a spent limit and pauses uploads as before. Size limits read "100 MiB" and "500 MiB", as the Registry and the docs state them. The size check and the upload are their own methods, with unit tests for the upload cap, a streamed download past the cap, and the retry. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…rnings for real limits - An upload retried after a short refusal waits up to half the wait again, by its artifact's key, so uploads refused together don't all retry together. It doesn't go again if uploads were paused while it waited. - A pause of 5 seconds or less no longer uses up its kind's one warning, which a longer limit later needs. - Tests pin the 5-second boundary, the re-check and the spread. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…leave a conflicting upload to the other A refusal of 5 seconds or less gets its own once-a-run notice, apart from the warning for a spent limit, including an upload dropped because uploads were paused while it waited to retry. An upload answered 409, which another upload of the same artifact is storing, ends quietly. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… wait, and note busy skips in LPM's own words A lookup refused for 5 seconds or less goes once more after the wait, plus its share of the spread, as uploads do, unless lookups were paused meanwhile; a cache hit is worth the wait. The busy notice is a skipped row in LPM's own words, and only for requests not already paused by a spent limit, whose warning covers them. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… retries per run The busy notice was held back while a pause had more than 5 seconds left, so a spent limit's last seconds read as a busy server. The CLI now records which pauses are spent limits when it takes them. Retry jitter hashes the artifact's key with a seed drawn each run, so parallel CI jobs refused on the same key don't retry together. Tests cover nothing paused while a lookup waits, the lookup's 5-second boundary and spread, and the busy notice when a lookup's retry is cut short. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
An upload skipped because a lookup's short pause also pauses uploads now gets the once-a-run busy notice; a spent limit keeps its warning instead, and a read-only client stays silent. Lookups skipped while paused take the same path. Retry jitter is tested to hold per key for the run. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…e run A 403 on an upload stops uploads for the run: the token can't write there, and every later upload would only spend the server's limit for refused requests. A 403 on a lookup stops lookups and uploads. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Companion to tolgaergin/a-package-manager#233. The LPM.dev Registry now limits remote cache requests per account, answers a request past a limit with 429 and
Retry-After, and stores artifacts up to 100 MiB.What changes
crates/lpm-cli/src/commands/remote_cache.rs:Retry-After. The wait comes from theRetry-Afterheader (seconds or an HTTP date), else the body'sretryAfter, else a minute, and is kept between a second and a day. The lookup or upload is treated as a miss or skipped, the task builds as it would without a remote cache, and the CLI uses the cache again once the wait ends.Remote cache limit reached: 300 uploads a minute; skipping remote cache uploads for 42 seconds. Before this, any earlier warning hid the limit's.Retry-After(5 s at most), as the Registry answers when the account has as many uploads in flight as it may or another upload holds its cache, makes the CLI wait and send the upload again instead of dropping it and pausing other uploads. The wait adds up to half again, from the artifact's key hashed with a seed drawn afresh each run, so uploads refused together don't retry together, even in parallel CI jobs refused on the same key, and the upload doesn't go again if uploads or lookups were paused meanwhile. A longer wait is a spent limit and pauses uploads.remote cache is busy; skipping some uploads for a moment(or lookups). An upload skipped because a lookup's short pause pauses uploads too gets the uploads notice, since the lookups notice alone wouldn't say so. It isn't given for a request a spent limit already pauses, whose warning covers it, nor, for uploads, by a read-only client. The CLI records which pauses are spent limits (a wait over 5 seconds) when it takes them, rather than guessing from the time left, so a spent limit's last seconds don't read as a busy server.lpm cache statusreports a 429 as the limit and when to try again.httpdatebecomes a direct dependency; it was already in the lockfile through hyper.The docs follow in lpm-dev/rust-client-docs#389.
Testing
Workflow tests against a mock cache server:
Retry-Afterhas passed;lpm cache statusreports the limit and the wait.Unit tests cover
Retry-Afterparsing, the wait's bounds and fallbacks against a real HTTP response, pause ordering, per-kind warnings, per-server-and-team state, the upload cap, a download streamed past the cap with noContent-Length, an upload refused for a moment that goes once more and pauses nothing, and uploads pausing after a refused retry or a long wait.Mutation checks: 47 mutations across eight rounds, all caught. Round 3 adds tests for the 5-second boundary, the pause re-check, the spread and the warning rule; round 4 for the spread at the call site, the boundary for both kinds, the re-check seeing a lookup pause, the busy notice and its own flag, and the quiet 409; round 5 for the lookup retry and its re-check, the notice's text, and no notice during a spent limit; round 6 for spent limits told from busy pauses (uploads covered by a lookup limit, a long limit marked spent, a busy pause not), nothing paused while a lookup waits, the lookup's 5-second boundary and spread, and the busy notice when a lookup's retry is cut short; round 7 for the notice on uploads and lookups skipped while paused, none for a read-only client, and jitter that holds per key for the run; round 8 for uploads and lookups stopped after a 403, and a refused lookup stopping uploads too.
The whole CI gate passes locally on d14cfda, with every workspace member rebuilt from this branch:
cargo clippy --workspace --all-targets --locked -- -D warnings,cargo fmt --check,cargo build --workspace --lockedcargo test -p lpm-cli --bin lpm-rs -- --test-threads=1: 5,435 passedrunandcacheworkflow tests with the hermetic CLI: 179 passed🤖 Generated with Claude Code