feat(xy): exclusive pidfile guard
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::Write;
|
||||
use std::os::unix::fs::OpenOptionsExt;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PidFile {
|
||||
path: PathBuf,
|
||||
_file: File,
|
||||
}
|
||||
|
||||
impl PidFile {
|
||||
pub fn acquire(path: &Path) -> std::io::Result<Self> {
|
||||
let mut f = OpenOptions::new()
|
||||
.write(true).create_new(true).mode(0o600).open(path)?;
|
||||
writeln!(f, "{}", std::process::id())?;
|
||||
Ok(Self { path: path.to_path_buf(), _file: f })
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for PidFile {
|
||||
fn drop(&mut self) { let _ = std::fs::remove_file(&self.path); }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use tempfile::tempdir;
|
||||
|
||||
#[test]
|
||||
fn acquire_then_second_fails() {
|
||||
let dir = tempdir().unwrap();
|
||||
let p = dir.path().join("x.pid");
|
||||
let _g = PidFile::acquire(&p).unwrap();
|
||||
let err = PidFile::acquire(&p).unwrap_err();
|
||||
assert_eq!(err.kind(), std::io::ErrorKind::AlreadyExists);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drop_removes_file() {
|
||||
let dir = tempdir().unwrap();
|
||||
let p = dir.path().join("x.pid");
|
||||
{ let _g = PidFile::acquire(&p).unwrap(); assert!(p.exists()); }
|
||||
assert!(!p.exists());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user