refactor: extract write_json_atomic helper, DRY 8 call sites
Move the crash-safe write-then-rename pattern into zesdex-utils::write_json_atomic and apply it across: - zesdex-cms: app_config_repo, conversation_repo, settings_repo - zesdex-iam: oauth_repo, session_repo - zesdex-entities: Conversation::save_conversation, Session::save Excluded (non-JSON format): - rewind_blob_repo (binary blob) - memory_repo (markdown + frontmatter, not JSON) - session_lock (PID string, not JSON) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
9a6ab62562
commit
4cd38c9291
@@ -18,3 +18,4 @@ url.workspace = true
|
||||
reqwest.workspace = true
|
||||
tokio.workspace = true
|
||||
tracing.workspace = true
|
||||
zesdex-utils.workspace = true
|
||||
|
||||
@@ -58,26 +58,19 @@ impl Session {
|
||||
/// Persist this session's metadata to `session.json`, atomically
|
||||
/// with fsync for crash safety.
|
||||
///
|
||||
/// Flow: ensure the session directory exists → serialize to pretty
|
||||
/// JSON → write to `session.json.tmp` → fsync → rename over
|
||||
/// `session.json` → fsync parent directory.
|
||||
/// Flow: ensure the session directory exists → atomically write
|
||||
/// pretty-printed JSON via `write_json_atomic`.
|
||||
///
|
||||
/// Why: write-then-rename avoids a torn/partial `session.json` if
|
||||
/// interrupted mid-write; fsync before rename ensures the data is
|
||||
/// on disk before the rename makes it visible.
|
||||
///
|
||||
/// Return: `Ok(())` on success, or an `io::Error` from any step.
|
||||
pub fn save(&self, base_dir: &Path) -> std::io::Result<()> {
|
||||
/// Return: `Ok(())` on success, or an `anyhow::Error` from any step.
|
||||
pub fn save(&self, base_dir: &Path) -> anyhow::Result<()> {
|
||||
let dir = self.session_dir(base_dir);
|
||||
std::fs::create_dir_all(&dir)?;
|
||||
let path = dir.join("session.json");
|
||||
let data = serde_json::to_string_pretty(self)?;
|
||||
let tmp = dir.join("session.json.tmp");
|
||||
std::fs::write(&tmp, data)?;
|
||||
let f = std::fs::File::open(&tmp)?;
|
||||
f.sync_all()?;
|
||||
std::fs::rename(&tmp, path)?;
|
||||
let _ = std::fs::File::open(&dir).and_then(|d| d.sync_all());
|
||||
zesdex_utils::write_json_atomic(&path, self, None)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -77,20 +77,14 @@ impl Conversation {
|
||||
/// Persist the conversation to a JSON file at the given base directory.
|
||||
///
|
||||
/// Flow: compute path from `session_id` → ensure directory exists →
|
||||
/// serialize to pretty JSON → write-then-rename with fsync.
|
||||
/// atomically write pretty-printed JSON via `write_json_atomic`.
|
||||
///
|
||||
/// Return: `Ok(())` on success, or an `io::Error` from any step.
|
||||
pub fn save_conversation(&self, base_dir: &std::path::Path) -> std::io::Result<()> {
|
||||
/// Return: `Ok(())` on success, or an `anyhow::Error` from any step.
|
||||
pub fn save_conversation(&self, base_dir: &std::path::Path) -> anyhow::Result<()> {
|
||||
let dir = base_dir.join("sessions").join(&self.session_id);
|
||||
std::fs::create_dir_all(&dir)?;
|
||||
let path = dir.join("conversation.json");
|
||||
let data = serde_json::to_string_pretty(self)?;
|
||||
let tmp = dir.join("conversation.json.tmp");
|
||||
std::fs::write(&tmp, data)?;
|
||||
let f = std::fs::File::open(&tmp)?;
|
||||
f.sync_all()?;
|
||||
std::fs::rename(&tmp, path)?;
|
||||
let _ = std::fs::File::open(&dir).and_then(|d| d.sync_all());
|
||||
zesdex_utils::write_json_atomic(&path, self, None)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user