Skip to content

Commit

Permalink
#61: Add --restart-delay option
Browse files Browse the repository at this point in the history
  • Loading branch information
mtkennerly committed Jan 17, 2025
1 parent e5effe6 commit 5f1ace6
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 0 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## Unreleased

* Added: `--restart-delay` option.

## v1.6.0 (2024-11-16)

* Added: `--path-prepend` option.
Expand Down
21 changes: 21 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,10 @@ pub struct CommonOpts {
)]
pub restart_if_not: Vec<i32>,

/// How long to wait before restarting the wrapped process
#[clap(long, value_name = "ms")]
pub restart_delay: Option<u64>,

/// How long to wait in milliseconds between sending the wrapped process
/// a ctrl-C event and forcibly killing it [default: 3000]
#[clap(long, value_name = "ms")]
Expand Down Expand Up @@ -586,6 +590,23 @@ speculate::speculate! {
}
}

it "accepts --restart-delay" {
check_args(
&["shawl", "run", "--restart-delay", "1500", "--", "foo"],
Cli {
sub: Subcommand::Run {
name: s("Shawl"),
cwd: None,
common: CommonOpts {
restart_delay: Some(1500),
command: vec![s("foo")],
..Default::default()
}
}
},
);
}

it "accepts --stop-timeout" {
check_args(
&["shawl", "run", "--stop-timeout", "500", "--", "foo"],
Expand Down
18 changes: 18 additions & 0 deletions src/control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ pub fn add_service(name: String, cwd: Option<String>, dependencies: &[String], o

fn construct_shawl_run_args(name: &str, cwd: &Option<String>, opts: &CommonOpts) -> Vec<String> {
let mut shawl_args = vec!["run".to_string(), "--name".to_string(), quote(name)];
if let Some(delay) = opts.restart_delay {
shawl_args.push("--restart-delay".to_string());
shawl_args.push(delay.to_string());
}
if let Some(st) = opts.stop_timeout {
shawl_args.push("--stop-timeout".to_string());
shawl_args.push(st.to_string());
Expand Down Expand Up @@ -307,6 +311,20 @@ speculate::speculate! {
);
}

it "handles --restart-delay" {
assert_eq!(
construct_shawl_run_args(
&s("shawl"),
&None,
&CommonOpts {
restart_delay: Some(1500),
..Default::default()
}
),
vec!["run", "--name", "shawl", "--restart-delay", "1500"],
);
}

it "handles --stop-timeout" {
assert_eq!(
construct_shawl_run_args(
Expand Down
28 changes: 28 additions & 0 deletions src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,31 @@ pub fn run_service(start_arguments: Vec<std::ffi::OsString>) -> windows_service:
None => windows::Win32::System::Threading::INHERIT_CALLER_PRIORITY.0,
};

let mut restart_after: Option<std::time::Instant> = None;

debug!("Entering main service loop");
'outer: loop {
if let Some(delay) = restart_after {
match shutdown_rx.recv_timeout(std::time::Duration::from_millis(1)) {
Ok(_) | Err(std::sync::mpsc::RecvTimeoutError::Disconnected) => {
info!("Cancelling before launch");
break 'outer;
}
Err(std::sync::mpsc::RecvTimeoutError::Timeout) => (),
};

let now = std::time::Instant::now();
if now < delay {
let step = (delay - now).min(std::time::Duration::from_millis(50));
debug!("Sleeping another {} ms", step.as_millis());
std::thread::sleep(step);
continue;
} else {
info!("Restart delay is complete");
restart_after = None;
}
}

info!("Launching command");
let should_log_cmd = !&opts.no_log_cmd;
let mut child_cmd = std::process::Command::new(&program);
Expand Down Expand Up @@ -354,6 +377,11 @@ pub fn run_service(start_arguments: Vec<std::ffi::OsString>) -> windows_service:
if let Err(e) = stderr_logger.join() {
error!("Unable to join stderr logger thread: {:?}", e);
}

if let Some(delay) = opts.restart_delay {
info!("Delaying {delay} ms before restart");
restart_after = Some(std::time::Instant::now() + std::time::Duration::from_millis(delay));
}
}
debug!("Exited main service loop");

Expand Down
12 changes: 12 additions & 0 deletions tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,5 +232,17 @@ speculate::speculate! {
).unwrap();
assert!(pattern.is_match(&log));
}

it "waits between restarts with --restart-delay" {
run_shawl(&["add", "--name", "shawl", "--restart-delay", "180", "--env", "RUST_LOG=shawl=debug", "--", &child(), "--exit", "1"]);
run_cmd(&["sc", "start", "shawl"]);
std::thread::sleep(std::time::Duration::from_millis(500));
run_cmd(&["sc", "stop", "shawl"]);

let log = std::fs::read_to_string(log_file()).unwrap();
assert!(log.contains("Delaying 180 ms before restart"));
assert!(log.lines().filter(|line| line.contains("Sleeping another")).count() > 1);
assert!(log.contains("Restart delay is complete"));
}
}
}

0 comments on commit 5f1ace6

Please sign in to comment.