feat(loop): port run_loop.sh to Python lib_py.loop with thin wrapper and strict parser (Phase 3)

This commit is contained in:
Godopu committed 2026-09-07 09:04:49 +09:00
1 parent e1203166d9
commit 8cd256cc7a
8 files changed
+1275 -7

No files matched your search

+53
View File
@@ -0,0 +1,53 @@
"""Atomic loop checkpoint management.
Issue #5 Phase 3.
Saves and restores loop progress (.mam/loop-checkpoint.json) across
signal-triggered quiesce or resumes.
"""
from __future__ import annotations
import json
import os
from pathlib import Path
from typing import Any, Dict, Optional
def save_checkpoint(checkpoint_path: str | Path, data: Dict[str, Any]) -> None:
"""Atomically write loop state to a checkpoint file."""
path = Path(checkpoint_path)
path.parent.mkdir(parents=True, exist_ok=True)
tmp_path = path.with_suffix(f".tmp.{os.getpid()}")
try:
with open(tmp_path, "w", encoding="utf-8") as f:
json.dump(data, f, indent=2)
f.flush()
os.fsync(f.fileno())
tmp_path.replace(path)
finally:
if tmp_path.exists():
try:
tmp_path.unlink()
except OSError:
pass
def load_checkpoint(checkpoint_path: str | Path) -> Optional[Dict[str, Any]]:
"""Load loop state from a checkpoint file if present, else None."""
path = Path(checkpoint_path)
if not path.is_file():
return None
try:
with open(path, "r", encoding="utf-8") as f:
return json.load(f)
except (OSError, json.JSONDecodeError):
return None
def remove_checkpoint(checkpoint_path: str | Path) -> None:
"""Safely remove a checkpoint file."""
path = Path(checkpoint_path)
try:
path.unlink(missing_ok=True)
except OSError:
pass