Keep concurrent usage collectors off one shared temp file (#6654)
Two Claude collectors running at once both wrote the cache through a temp path derived from the target, so the second replace found the file already moved away and crashed the update with a FileNotFoundError. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
f8c235a5e4
commit
e4d85bd037
@@ -23,6 +23,7 @@ import os
|
||||
import re
|
||||
import sqlite3
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
@@ -230,9 +231,21 @@ def read_fresh_json(path: Path, max_age_seconds: float) -> dict[str, Any] | None
|
||||
|
||||
|
||||
def write_json(path: Path, payload: dict[str, Any]) -> None:
|
||||
tmp = path.with_suffix(path.suffix + ".tmp")
|
||||
tmp.write_text(json.dumps(payload, separators=(",", ":"), sort_keys=True) + "\n", encoding="utf-8")
|
||||
tmp.replace(path)
|
||||
# A temp name unique to this writer, not derived from the target: several
|
||||
# collectors can run at once (the update command backgrounds one per agent,
|
||||
# the panel refreshes on its own), and a shared temp path means the second
|
||||
# replace finds the first one's file already moved away.
|
||||
handle_fd, tmp_name = tempfile.mkstemp(dir=path.parent, prefix=path.name + ".", suffix=".tmp")
|
||||
tmp = Path(tmp_name)
|
||||
try:
|
||||
with os.fdopen(handle_fd, "w", encoding="utf-8") as handle:
|
||||
handle.write(json.dumps(payload, separators=(",", ":"), sort_keys=True) + "\n")
|
||||
# mkstemp opens at 0600; these caches were world-readable before.
|
||||
tmp.chmod(0o644)
|
||||
tmp.replace(path)
|
||||
except BaseException:
|
||||
tmp.unlink(missing_ok=True)
|
||||
raise
|
||||
|
||||
|
||||
def cached_scan(projects_path: Path, max_age_seconds: float) -> dict[str, Any]:
|
||||
|
||||
Reference in New Issue
Block a user