refactor: use atomic_json_write instead of hand-rolled _write_payload

Replace 20 lines of manual os.open/O_EXCL/fdopen/fsync/os.replace with the
existing atomic_json_write() from utils.py, which is already used by 6+
modules and handles temp-file creation, fsync, atomic replace, mode
control, and owner preservation. The only novel helper (_fsync_directory)
is retained — atomic_json_write does not do directory fsync.

Update test_flush_write_failure_leaves_no_recovery_file to monkeypatch
utils.os.replace (the new call path) instead of gateway.shutdown_flush.os.replace.
This commit is contained in:
kshitij 2026-07-29 00:22:50 +05:00 committed by kshitij
parent 72024950cf
commit 720cdd1d14
2 changed files with 9 additions and 22 deletions

View File

@ -55,29 +55,16 @@ def _fsync_directory(path: Path) -> None:
def _write_payload(flush_dir: Path, payload: Dict[str, Any]) -> None:
"""Atomically write one private, uniquely named recovery payload."""
from utils import atomic_json_write
file_id = uuid.uuid4().hex
final_path = flush_dir / f"pending-{file_id}.json"
temp_path = flush_dir / f".pending-{file_id}.tmp"
file_descriptor = -1
try:
file_descriptor = os.open(
temp_path,
os.O_WRONLY | os.O_CREAT | os.O_EXCL,
0o600,
)
with os.fdopen(file_descriptor, "w", encoding="utf-8") as handle:
file_descriptor = -1 # The file object now owns the descriptor.
json.dump(payload, handle, ensure_ascii=False, default=str)
handle.flush()
os.fsync(handle.fileno())
os.replace(temp_path, final_path)
except Exception:
if file_descriptor >= 0:
os.close(file_descriptor)
temp_path.unlink(missing_ok=True)
raise
atomic_json_write(
final_path,
payload,
mode=0o600,
default=str,
)
try:
_fsync_directory(flush_dir)

View File

@ -74,7 +74,7 @@ def test_flush_write_failure_leaves_no_recovery_file(tmp_path, monkeypatch):
def fail_replace(source, destination):
raise OSError("simulated replace failure")
monkeypatch.setattr("gateway.shutdown_flush.os.replace", fail_replace)
monkeypatch.setattr("utils.os.replace", fail_replace)
assert flush_pending_to_file({"session": "message"}, reason="test") == 0
assert list(flush_dir.iterdir()) == []