Refactor run on_update to make the behaviour clearer

This commit is contained in:
Félix Saparelli 2021-04-11 03:15:17 +12:00
parent 6cfe649228
commit 12d130c3f1
No known key found for this signature in database
GPG Key ID: B948C4BAE44FC474
1 changed files with 40 additions and 42 deletions

View File

@ -207,60 +207,56 @@ impl Handler for ExecHandler {
// Only returns Err() on lock poisoning. // Only returns Err() on lock poisoning.
fn on_update(&self, ops: &[PathOp]) -> Result<bool> { fn on_update(&self, ops: &[PathOp]) -> Result<bool> {
// We have four scenarios here: match (
// self.has_running_process(),
// 1. Just send a specified signal to the child, do nothing more self.args.restart, // kill the command if it's still running when a change comes in
// 2. Just spawn a process if there are no running processes in the background self.signal,
// 3. Send a specified signal to the child, wait for it to exit, then run the command again self.args.watch_when_idle, // ignore events emitted while the command is running
// 4. Send SIGTERM to the child, wait for it to exit, then run the command again ) {
// 5. Make sure the previous run was ended, then run the command again // Spawn a process when there are no running processes in the background
// (false, _, _, _) => {
let scenario = ( self.spawn(ops)?;
self.args.restart, }
self.signal.is_some(),
self.args.watch_when_idle,
);
let running_process = self.has_running_process();
match scenario {
// SIGHUP scenario: --signal was given, but --restart was not // SIGHUP scenario: --signal was given, but --restart was not
// Just send a signal (e.g. SIGHUP) to the child, do nothing more // Just send a signal (e.g. SIGHUP) to the child, do nothing more
(false, true, _) => signal_process(&self.child_process, self.signal, false), (true, false, Some(signal), _) => signal_process(&self.child_process, signal),
// Spawn a process when there are no running processes in the background
(_, _, true) => {
if !running_process {
self.spawn(ops)?;
}
}
// Custom restart behaviour (--restart was given, and --signal specified): // Custom restart behaviour (--restart was given, and --signal specified):
// Send specified signal to the child, wait for it to exit, then run the command again // Send specified signal to the child, wait for it to exit, then run the command again
(true, true, false) => { (_, true, Some(signal), false) => {
signal_process(&self.child_process, self.signal, true); signal_process(&self.child_process, signal);
wait_on_process(&self.child_process);
self.spawn(ops)?; self.spawn(ops)?;
} }
// Default restart behaviour (--restart was given, but --signal wasn't specified): // Default restart behaviour (--restart was given, but --signal wasn't specified):
// Send SIGTERM to the child, wait for it to exit, then run the command again // Send SIGTERM to the child, wait for it to exit, then run the command again
(true, false, false) => { (_, true, None, false) => {
let sigterm = signal::new(Some("SIGTERM".into())); signal_process(&self.child_process, Signal::SIGTERM);
wait_on_process(&self.child_process);
signal_process(&self.child_process, sigterm, true);
self.spawn(ops)?; self.spawn(ops)?;
} }
// Default behaviour (neither --signal nor --restart specified): // Default behaviour (neither --signal nor --restart specified):
// Make sure the previous run was ended, then run the command again // Make sure the previous run was ended, then run the command again
(false, false, false) => { (_, false, None, false) => {
signal_process(&self.child_process, None, true); wait_on_process(&self.child_process);
self.spawn(ops)?; self.spawn(ops)?;
} }
// Command is running and we're ignoring updates while it's running
(true, _, _, true) => {}
} }
// Handle once option for integration testing // Handle once option for integration testing
if self.args.once { if self.args.once {
signal_process(&self.child_process, self.signal, false); if let Some(signal) = self.signal {
signal_process(&self.child_process, signal);
}
wait_on_process(&self.child_process);
return Ok(false); return Ok(false);
} }
@ -328,18 +324,20 @@ fn wait_fs(
paths paths
} }
// signal_process sends signal to process. It waits for the process to exit if wait is true fn signal_process(process: &RwLock<Option<Process>>, signal: Signal) {
fn signal_process(process: &RwLock<Option<Process>>, signal: Option<Signal>, wait: bool) {
let guard = process.read().expect("poisoned lock in signal_process"); let guard = process.read().expect("poisoned lock in signal_process");
if let Some(ref child) = *guard { if let Some(ref child) = *guard {
if let Some(s) = signal { debug!("Signaling process with {}", signal);
child.signal(s); child.signal(signal);
} }
}
if wait {
debug!("Waiting for process to exit..."); fn wait_on_process(process: &RwLock<Option<Process>>) {
child.wait(); let guard = process.read().expect("poisoned lock in wait_on_process");
}
if let Some(ref child) = *guard {
debug!("Waiting for process to exit...");
child.wait();
} }
} }