fix: serialize daemon control commands

Fixes #10
This commit is contained in:
2026-07-13 22:02:11 +08:00
parent 1bcb9c828a
commit 599ead8391
9 changed files with 593 additions and 72 deletions
+40 -4
View File
@@ -1459,8 +1459,9 @@ impl OfficialUpdateLock {
continue;
}
return Err(anyhow::anyhow!(
"官方资源目录已被锁定 (locked):{}",
path.display()
"官方资源目录已被锁定 (locked):{}{}",
path.display(),
describe_lock_owner(&path)
));
}
Err(error) => {
@@ -1481,14 +1482,21 @@ impl OfficialUpdateLock {
impl Drop for OfficialUpdateLock {
fn drop(&mut self) {
let _ = fs::remove_file(&self.path);
let expected = std::process::id().to_string();
if fs::read_to_string(&self.path)
.map(|contents| contents.trim() == expected)
.unwrap_or(false)
{
let _ = fs::remove_file(&self.path);
}
}
}
fn remove_stale_lock(path: &Path) -> anyhow::Result<bool> {
let contents = fs::read_to_string(path).unwrap_or_default();
let Some(pid) = parse_lock_pid(&contents) else {
return Ok(false);
fs::remove_file(path)?;
return Ok(true);
};
if process_exists(pid) {
return Ok(false);
@@ -1498,6 +1506,15 @@ fn remove_stale_lock(path: &Path) -> anyhow::Result<bool> {
Ok(true)
}
fn describe_lock_owner(path: &Path) -> String {
let contents = fs::read_to_string(path).unwrap_or_default();
match parse_lock_pid(&contents) {
Some(pid) if process_exists(pid) => format!("owner_pid={pid} 仍在运行"),
Some(pid) => format!("owner_pid={pid} 已失效,可重新执行或 clean-stable 清理"),
None => "锁文件内容不是有效 PID,可执行 clean-stable 清理".to_string(),
}
}
fn parse_lock_pid(contents: &str) -> Option<u32> {
contents.trim().parse::<u32>().ok().filter(|pid| *pid > 0)
}
@@ -1716,6 +1733,25 @@ mod tests {
assert!(!config.lock_path().exists());
}
#[test]
fn non_dry_run_lock_removes_corrupt_pid_file() {
let temp = tempfile::TempDir::new().unwrap();
let config = OfficialUpdateConfig {
output_root: temp.path().to_path_buf(),
..OfficialUpdateConfig::default()
};
fs::create_dir_all(&config.output_root).unwrap();
fs::write(config.lock_path(), "not-a-pid").unwrap();
let lock = OfficialUpdateLock::acquire(&config).unwrap();
assert_eq!(
fs::read_to_string(config.lock_path()).unwrap(),
std::process::id().to_string()
);
drop(lock);
assert!(!config.lock_path().exists());
}
#[test]
fn update_run_can_be_cancelled_before_network_work() {
let temp = tempfile::TempDir::new().unwrap();