fix(ci): de-flake the two intermittent macOS test failures (#1222) - #1225
Merged
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (4)
🚧 Files skipped from review as they are similar to previous changes (4)
📝 WalkthroughWalkthroughThe PR retries interrupted file-lock operations, injects downloader retry timing for production and tests, and adds error-preserving spawn-lock acquisition with logging for swallowed I/O failures. ChangesReliability changes
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
zackees
force-pushed
the
fix/1222-deflake-macos-ci
branch
from
August 1, 2026 20:31
19126e6 to
8f512c8
Compare
Neither test was a regression; both surfaced once #1216/#1221 stopped the macOS job aborting before it reached the test step. Both assert exact outcomes over real OS resources under timing pressure. ## spawn_lock_is_exclusive_within_process `try_acquire_spawn_lock_at` used `.ok().flatten()`, collapsing a hard I/O error into the same `None` that means "another process holds the lock" — so when the third acquire failed, there was no way to tell which had happened. - Split into `try_acquire_spawn_lock_result_at` (propagates) and the existing swallowing wrapper (logs errno + kind, then returns `None`). The "a broken filesystem must never gate progress" contract for the production caller is unchanged; the failure is just no longer silent. - The test now uses the error-preserving variant, so a hard error reports the actual errno instead of a bare `assertion failed`. - Retry `EINTR` in `file_lock::try_acquire`, around both the `open` and the `flock`. `flock()` is interruptible by signals on macOS/BSD and fs2 returns the raw OS error, which our classifier doesn't recognize as contention — so an EINTR became a hard error. Correct regardless of whether it was the cause here. ## streaming_download_retries_chunk_stalls_five_times_without_output This was the only test combining `#[tokio::test(start_paused = true)]` with a real `TcpListener`, and it was the one that flaked. Paused time auto-advances whenever the runtime looks idle, but socket readiness comes from the OS reactor, not the virtual clock — so with the client parked on `chunk()` and the server on `sleep`, the clock could jump past a connection that was about to reach `accept()`, leaving `request_count` short of 5. Took the issue's preferred fix rather than the stopgap: extract the retry durations into a `RetryTiming` struct so the test drives the *same* retry logic on millisecond durations in real time. No `start_paused`, no reactor race, and the assertion stays at exactly 5 attempts instead of being weakened to `>= 1`. Runs in ~1s. `production_retry_timing_matches_the_constants` pins the seam to the real constants so the injection can't drift into a behavior change. Verified: the chunk-stall test passes 5/5 consecutive runs locally; clippy clean on all four crates. Co-Authored-By: Claude <noreply@anthropic.com>
…ng variant The new wrapper test asserted `try_acquire_spawn_lock_at(&path).is_some()` after release — and reproduced the exact #1222 flake on Ubuntu CI, on the same commit that had just passed, as a bare `assertion failed` with no errno. That is the defect this PR is about, not a bad test: the swallowing wrapper cannot distinguish "I/O error" from "another holder has it", so ANY re-acquire assertion through it is untestable by construction. Asserting that step through `try_acquire_spawn_lock_result_at` is the same correction the issue asks for on the original test. Two things worth recording: the flake is NOT macOS-only, and it lands on the post-release re-acquire rather than the release itself — which is consistent with the issue's "hard error misread as contention" theory and not with "macOS fails to release flock on close". The errno now logged by the wrapper is what should identify it next time. Co-Authored-By: Claude <noreply@anthropic.com>
zackees
force-pushed
the
fix/1222-deflake-macos-ci
branch
from
August 1, 2026 21:43
91cd72d to
1cf17b1
Compare
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.
Closes #1222.
Both tests, both fixed at the root rather than by weakening assertions. Neither was a regression — they only became visible once #1216/#1221 stopped the macOS job aborting before it reached the test step.
1.
spawn_lock_is_exclusive_within_processThe issue's key observation was that we couldn't tell why it failed, and that's the part fixed first:
.ok()collapsed a hard I/O error into the sameNonethat means "another process holds the lock."try_acquire_spawn_lock_result_atis a new error-propagating variant.try_acquire_spawn_lock_atkeeps the swallowing behavior — a broken filesystem must never gate daemon spawn — but now logs the errno and kind before returningNone. Production contract unchanged; the failure is just no longer invisible.assertion failed: third.is_some().EINTRis now retried infile_lock::try_acquire, around both theopenand theflock(candidate cause (a) in the issue).flock()is interruptible by signals on macOS/BSD,fs2returns the raw OS error, andlock_is_heldonly recognizesEWOULDBLOCK/lock_contended_error— so anEINTRbecame a hard error →.ok()→None→ that exact assertion. Retrying is correct whether or not it was the cause here. Bounded at 8 attempts so a continuous signal source can't spin forever.Candidate (b), fd exhaustion, is not separately addressed — but it now announces itself as
EMFILEin the log instead of looking like contention.2.
streaming_download_retries_chunk_stalls_five_times_without_outputAs the issue notes, this was the only test combining
start_paused = truewith a realTcpListener, and it was the one that flaked. Paused time auto-advances whenever the runtime looks idle, but socket readiness comes from the OS reactor, not the virtual clock — so with the client parked onchunk()and the server onsleep(120s), the clock could jump past a connection about to reachaccept(), leavingrequest_countbelow 5.I took the first suggested option, not the stopgap: the retry durations move into a
RetryTimingstruct, so the test drives the same retry logic on millisecond durations in real time.No
start_paused, no reactor race, andassert_eq!(count, 5)stays exact rather than being weakened to>= 1— the retry budget is the actual contract under test, so keeping it asserted is the point.production_retry_timing_matches_the_constantspins the seam toCHUNK_READ_TIMEOUT/RETRY_BACKOFFSso the test seam can't silently drift into a behavior change.Verification
Local repro of the macOS host isn't possible (per the issue: cross-compiling to
x86_64-apple-darwinfrom Windows fails onring), so this leans on CI plus what is checkable locally:soldr cargo test -p fbuild-packages-fetch -p fbuild-paths -p fbuild-core --libgreen.soldr cargo clippyclean on all four crates with-D warnings.fbuild-pathsgains atracingdependency for the errno log line.Worth watching this PR's
Check (macos-latest)specifically — that's the real test of the fix.🤖 Generated with Claude Code
Summary by CodeRabbit