Skip to content

Write the cached registry file atomically - #382

Merged
g5t merged 4 commits into
mccode-dev:mainfrom
tkittel:registry-file-atomic-write
Oct 9, 2026
Merged

g5t merged 4 commits into
mccode-dev:mainfrom
tkittel:registry-file-atomic-write

Conversation

@tkittel

@tkittel tkittel commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Another small potential race condition spotted in our new CI. Fix looks simple enough.

Claude says:

GitHubRegistry wrote its cached registry file in place. When several processes create the same registry at the same time (e.g. two notebooks run in parallel with an empty cache), one of them can read the file while another is writing it, and gets an empty or truncated registry, or fails with:

ValueError: not enough values to unpack (expected 2, got 1)

The file is now written to a temporary file which is then renamed, as the in-memory registries already do. If the rename fails (on Windows, while another process is reading the file), the temporary file is dropped, since the other process wrote the same content.

The new test creates the same registry (20,000 entries) with 8 processes at once, 5 times, and takes about a second. Without the fix it fails in every run.

🤖 Generated with Claude Code

tkittel and others added 2 commits October 9, 2026 11:46
GitHubRegistry wrote its cached registry file in place, so another process
reading it at the same time could get an empty or truncated registry, or fail
with "ValueError: not enough values to unpack". It is now written to a
temporary file which is then renamed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When several processes download the same file, pooch moves each download
into place with shutil.move, which on Windows falls back to copying onto the
file when another process has already put it there, and fails with WinError
32 if a process has the file open at that moment. pooch_fetch now retries
the fetch a few times, which then finds the finished file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@tkittel

tkittel commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

@g5t Claude had a look at that spurious test failure, the proposed solution is added to this PR in a second commit. Claude says:

As discussed, the second commit fixes the failure of test_parallel_fetch_into_new_directories on Windows, which is a second race in pooch, not a flaky test:

pooch downloads to a temporary file and moves it into place with shutil.move. On Windows, the rename fails when another process already put the same file there, so shutil.move falls back to copying onto it, which fails with PermissionError: [WinError 32] The process cannot access the file because it is being used by another process if another process has the file open at that moment. This is not covered by the pooch PR (fatiando/pooch#554), which only fixes the directory creation.

pooch_fetch() now retries the fetch a few times on PermissionError (waiting at most about a second in total). The retry then finds the finished file and only checks its hash. A new test checks the retry with a fake pooch; the race itself only happens on Windows, where test_parallel_fetch_into_new_directories exercises it.

@tkittel

tkittel commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

Claude also privately admitted to me:

Since the race is intermittent, one green Windows run doesn't prove much. If the test still fails occasionally after this, I'll need to look again.

@tkittel

tkittel commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

well, that worry was premature claude :-)

Comment thread tests/test_registry_file_parallel.py
On Windows, opening the registry file can fail with PermissionError while
another process replaces it with its own copy, as seen in
test_parallel_registry_file. The read is now retried a few times.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@tkittel

tkittel commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

Claude fixed the new failure as well, probably. Claude:

The Windows 3.14 job then failed in the new test_parallel_registry_file, with PermissionError(13, 'Permission denied') in one of the 8 processes: on Windows, opening the cached registry file can fail for a moment while another process replaces it with its own (identical) copy. The third commit retries that read a few times, as for the pooch fetches.

@g5t
g5t merged commit a99c81d into mccode-dev:main Oct 9, 2026
14 checks passed
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.

2 participants