fix: don't cache failed rustc-wrapper output in rustc info cache#17000
fix: don't cache failed rustc-wrapper output in rustc info cache#17000coleleavitt wants to merge 1 commit into
Conversation
When a rustc wrapper (e.g., sccache) fails transiently, the failure output was cached in target/.rustc_info.json and replayed on every subsequent build. Since the cache fingerprint is based on binary mtime/size and toolchain metadata — not runtime state — the cached failure was never invalidated, requiring manual deletion of the file. This changes cached_output() to only persist successful command results. Failed outputs are returned as errors but not inserted into the cache, allowing subsequent builds to retry the command and succeed once the transient issue resolves. Also skip writing the cache file on Drop when there are no cached outputs to persist.
|
r? @epage rustbot has assigned @epage. Use Why was this reviewer chosen?The reviewer was selected based on:
|
|
This appears to be an attempt to fix #15358, is that right? If that is the case then this isn't as straightforward as "this shouldn't be done". Either way, the next step is to bring your use case to that issue or a new issue as our contrib docs ask for us to work on understanding the problem and potential solutions as well as to get buy-in for a solution before moving onto a PR. |
|
You're right — apologies for putting the PR before the design discussion. I've now posted a detailed write-up on #15358 with my concrete use case (sccache transient failures permanently poisoning Happy to leave this PR open as a reference implementation while #15358 gets triaged, or close it and re-open once/if the issue lands Either way I'll wait for buy-in on direction before pushing anything else here. |
Summary
When a
rustc_wrapper(e.g.,sccache) fails transiently, the failure output gets cached intarget/.rustc_info.jsonand is replayed on every subsequentcargo build. Since the cache fingerprint is derived from binary mtime/size and toolchain metadata — not runtime state — the poisoned cache entry is never invalidated, permanently breaking builds until the user manually deletes the file.The Bug
Cache::cached_output()unconditionally inserts command output into the cache regardless of exit status. On a cache hit, it replays whatever was stored — including failures. The fingerprint only changes when the rustc/wrapper binary or toolchain changes, so a transient failure (server timeout, permission error, etc.) becomes permanent.Real-world trigger:
sccacheserver occasionally returnsEPERMon startup race conditions. One failure poisons the cache and every build afterward fails with the same error — even aftersccacherecovers.The Fix
Dropwhen there are no outputs to persist (avoids writing empty/useless cache files).Testing
rustc_info_cache_with_wrappersto verify failures are retried rather than replayed from cache.rustc_info_cache_transient_failure_recoverytest that simulates a wrapper failing then recovering, verifying the build succeeds on retry without manual intervention.