Radish alpha
r
rad:zwTxygwuz5LDGBq255RA2CbNGrz8
Radicle CI broker
Radicle
Git
Could replace the `timeoutcmd` module with a custom `timeout` command implementation
Open liw opened 5 months ago simplification timeout

The following seems to work well enough and is much simpler than the timeoutcmd module.

use std::{
    ffi::OsString,
    process::Command,
    thread::{sleep, spawn},
    time::Duration,
};

use clap::Parser;
use libc::{SIGKILL, kill};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let args = Args::parse();

    let mut cmd = Command::new(&args.argv0);
    cmd.args(&args.args);
    let mut child = cmd.spawn()?;

    let child_pid = i32::try_from(child.id())?;
    let timeout = args.timeout;
    let _handler = spawn(move || terminate_after(timeout, child_pid));

    child.wait()?;

    Ok(())
}

fn terminate_after(t: Duration, child: i32) {
    sleep(t);
    unsafe {
        kill(child, SIGKILL);
    }
    eprintln!("kill child process {child} for taking too long");
}

/// Run a command, but terminate it if takes too long.
#[derive(Debug, Parser)]
struct Args {
    /// Maximum duration, in seconds, how long the command may take.
    #[clap(value_parser = parse_duration)]
    timeout: Duration,

    /// Name of command to run.
    argv0: OsString,

    /// Arguments to command.
    args: Vec<OsString>,
}

fn parse_duration(arg: &str) -> Result<Duration, std::num::ParseIntError> {
    let seconds = arg.parse()?;
    Ok(std::time::Duration::from_secs(seconds))
}