Skip to content

Use unique temp filenames for atomic state writes - #188

Merged
raine merged 2 commits into
raine:mainfrom
aserper:fix/atomic-write-tmp
Jul 2, 2026
Merged

Use unique temp filenames for atomic state writes#188
raine merged 2 commits into
raine:mainfrom
aserper:fix/atomic-write-tmp

Conversation

@aserper

@aserper aserper commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Use a unique temp filename per writer for atomic state writes (pid + nanos) instead of a shared .json.tmp
  • Applies to both StateStore::write_atomic and the Codex status write_atomic
  • Relax the leftover-temp-file test assertion to catch any .tmp suffix

Why

Concurrent status writes for the same pane (e.g. duplicate status extensions firing at once) shared one .json.tmp path, so one writer could clobber another's temp file before the atomic rename. The rename itself is atomic on the same filesystem; only the temp path needs to be unique per writer.

Tests

  • cargo test --quiet -- --test-threads=1

Split out of #184 where it was bundled with unrelated Pi status changes.

The shared `.json.tmp` path meant concurrent status writes for the same
pane could clobber each other's temp file before the atomic rename. Give
each writer a unique temp filename (pid + nanos) so only the rename is
shared, and relax the test assertion to catch any leftover `.tmp` suffix.
The state write fix needs a temp file strategy that is unique across
concurrent writers and consistent across every atomic write path. The pid and
clock based name still allows same-process collisions on systems with coarse
clock resolution, and each copied helper needs the same cleanup behavior.

This adds a shared write_atomic helper backed by tempfile so temp names are
created exclusively in the target directory. The helper removes stale temp
files matching its target-specific prefix, writes and flushes the content, and
persists the temp file over the target. Agent state, Codex status, run result,
and GitHub PR cache writes all use the shared helper.

The focused tests cover target replacement, temp cleanup after successful
writes, and preservation of fresh temp files.
@raine
raine merged commit 5b7d7a0 into raine:main Jul 2, 2026
@raine

raine commented Jul 2, 2026

Copy link
Copy Markdown
Owner

Thank you

raine added a commit that referenced this pull request Jul 2, 2026
* Use unique temp filenames for atomic state writes

The shared `.json.tmp` path meant concurrent status writes for the same
pane could clobber each other's temp file before the atomic rename. Give
each writer a unique temp filename (pid + nanos) so only the rename is
shared, and relax the test assertion to catch any leftover `.tmp` suffix.

* use shared atomic write helper

The state write fix needs a temp file strategy that is unique across
concurrent writers and consistent across every atomic write path. The pid and
clock based name still allows same-process collisions on systems with coarse
clock resolution, and each copied helper needs the same cleanup behavior.

This adds a shared write_atomic helper backed by tempfile so temp names are
created exclusively in the target directory. The helper removes stale temp
files matching its target-specific prefix, writes and flushes the content, and
persists the temp file over the target. Agent state, Codex status, run result,
and GitHub PR cache writes all use the shared helper.

The focused tests cover target replacement, temp cleanup after successful
writes, and preservation of fresh temp files.

---------

Co-authored-by: aserper <aserper@users.noreply.github.com>
Co-authored-by: Raine Virta <raine.virta@gmail.com>
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