use std::time::Duration;
use tokio::process::{Child, Command};
use crate::error::{Error, Result};
use crate::mechanism::Mechanism;
use crate::stats::ProcessGroupStats;
use crate::sys::Job;
#[derive(Debug, Clone)]
pub struct ProcessGroupOptions {
pub shutdown_timeout: Duration,
pub escalate_to_kill: bool,
}
impl Default for ProcessGroupOptions {
fn default() -> Self {
Self {
shutdown_timeout: Duration::from_secs(2),
escalate_to_kill: true,
}
}
}
pub struct ProcessGroup {
job: Job,
options: ProcessGroupOptions,
}
impl ProcessGroup {
pub fn new() -> Result<Self> {
Self::with_options(ProcessGroupOptions::default())
}
pub fn with_options(options: ProcessGroupOptions) -> Result<Self> {
let job = Job::new()?;
Ok(Self { job, options })
}
pub fn spawn(&self, cmd: &mut Command) -> Result<Child> {
let child = self.job.spawn(cmd).map_err(|source| Error::Spawn {
program: program_name(cmd),
source,
})?;
Ok(child)
}
pub fn adopt(&self, child: &Child) -> Result<()> {
self.job.adopt(child)?;
Ok(())
}
pub fn terminate_all(&self) -> Result<()> {
self.job.kill_all()?;
Ok(())
}
pub async fn shutdown(self) -> Result<()> {
self.job
.graceful_shutdown(self.options.shutdown_timeout, self.options.escalate_to_kill)
.await?;
Ok(())
}
pub fn stats(&self) -> Result<ProcessGroupStats> {
let stats = self.job.stats()?;
Ok(stats)
}
pub fn mechanism(&self) -> Mechanism {
self.job.mechanism()
}
}
fn program_name(cmd: &Command) -> String {
cmd.as_std().get_program().to_string_lossy().into_owned()
}