Expand description
processkit — child-process management for Rust.
Two layers:
ProcessGroup— a kill-on-drop container for a process tree. Every child spawned into the group, and everything those children spawn, dies with the group, so an exiting or panicking owner never leaks subprocesses. Containment is a Windows Job Object, a Linux cgroup v2 (with a POSIX process-group fallback), a POSIX process group on macOS/BSD, or nothing on other targets — observable viaMechanism. The whole tree can be signalled (ProcessGroup::signal, seeSignal), paused/resumed (ProcessGroup::suspend/ProcessGroup::resume), and inspected (ProcessGroup::members);wait_anyraces several running processes and reports the first to exit.- runner — async run-and-capture built on the group. Describe a run with
Command, then drive it to completion (Command::output_string,Command::run, …) orstartit for streaming and interactive I/O. TheProcessRunnertrait runs commands to completion and is the mock seam (seeScriptedRunner). ASupervisorkeeps a command alive — restarting it per policy with backoff — whereCommand::retrymerely replays one run to success. Readiness probes (RunningProcess::wait_for_line/wait_for_port/wait_for) wait until a started child is actually ready instead of sleeping. APipeline(Command::pipe) chains commands stdout→stdin without a shell — one shared group, pipefail outcome. Spawn-time sandboxing knobs:Command::inherit_env(env allow-list),Command::uid/Command::gid(Unix privilege drop),Command::setsid,Command::create_no_window.
Async throughout (tokio). Errors are the structured Error; a non-zero
exit is reported in ProcessResult, not raised, until you call
ProcessResult::ensure_success.
Beyond this page, the repository ships a narrative guide set — a task-oriented cookbook (“I want to …” → snippet), a deep guide per capability, and every per-platform caveat collected in one place.
Run vocabulary — one verb, one meaning, at every layer (Command,
ProcessRunner/ProcessRunnerExt, CliClient):
run— require a zero exit and return stdout as aString, trailing whitespace trimmed (trim_end: the final newline is noise, but leading whitespace can be significant).run_unit— the same, discarding the output.output— return the fullProcessResult; a non-zero exit is not an error here. (Commandsplits the verb by payload:output_string/output_bytes.)exit_code— the exit code, with a missing code surfaced as an error. (On aProcessResult,codeis the plainOption<i32>accessor —Nonefor a timeout/signal kill, never a-1sentinel.)probe— run a predicate and read its exit code as abool:0→true,1→false, anything else is an error (git diff --quiet, …).
use processkit::Command;
// Capture output; a non-zero exit does not error on its own.
let result = Command::new("git").args(["rev-parse", "HEAD"]).output_string().await?;
println!("HEAD is {}", result.stdout().trim());
// Or require success and get trimmed stdout directly.
let version = Command::new("cargo").arg("--version").run().await?;§Recipes
use processkit::{Command, Error};
// Exit code *is* the answer (0 = yes, 1 = no; anything else errors):
let clean = Command::new("git").args(["diff", "--quiet"]).probe().await?;
// Retry a transient failure (replays the command; classifier inspects the error):
let fetched = Command::new("git")
.args(["fetch", "--quiet"])
.timeout(Duration::from_secs(10))
.retry(3, Duration::from_millis(200), |e| {
matches!(e, Error::Timeout { .. })
|| e.diagnostic().is_some_and(|m| m.contains("Could not resolve host"))
})
.run()
.await;
// A friendly failure message — stderr, falling back to stdout (git writes
// `CONFLICT …` / `nothing to commit` there):
if let Err(e) = Command::new("git").args(["merge", "topic"]).run().await {
eprintln!("merge failed: {}", e.diagnostic().unwrap_or("(no output)"));
}
// Set an env var once for every command (typed CLI wrapper):
use processkit::CliClient;
let git = CliClient::new("git").default_env("GIT_TERMINAL_PROMPT", "0");
let _ = git.run(git.command(["status", "--porcelain"])).await?;§Features
Every flag is additive and gates visibility only — the kill-on-drop tree guarantee is unconditional in every configuration.
stats(default) — resource measurement:ProcessGroupStats,ProcessGroup::stats(plus thesample_statstime-series sampler), the per-processRunningProcess::cpu_time/peak_memory_bytesdiagnostics, and theRunningProcess::profilerun summary. Disable (default-features = false) to compile the accounting code out.process-control(default) — tree control beyond contain+kill:SignalandProcessGroup::{signal, suspend, resume, members, adopt}.limits— whole-tree resource caps:ResourceLimits, thememory_max/max_processes/cpu_quotabuilders onProcessGroupOptions, andError::ResourceLimit. Impliesstats.mock— themockall-generatedMockRunnerfor consumers’ tests.tracing—tracingevents on theprocesskittarget: spawn and exit (program/pid/mechanism), timeout and cancellation firing, group terminate/shutdown, retry attempts, supervisor restarts and storm pauses, and teardown anomalies (stdin-writer failures, pump overruns). Never logs argv or environment values.cancellation— first-class run cancellation:Command::cancel_onties a run to aCancellationToken; cancelling it kills the tree and every consuming path resolves toError::Cancelled. Re-exportsCancellationToken(fromtokio-util).record— record/replay cassettes over theProcessRunnerseam:RecordReplayRunnerrecords realInvocation → ProcessResultpairs to a JSON fixture once, then replays them hermetically — no subprocess in CI. Pulls inserde+serde_json.
Macros§
- cli_
client - Scaffold a typed CLI-wrapper struct around a
CliClient.
Structs§
- Cancellation
Token cancellation - Re-exported (under the
cancellationfeature) so callers canuse processkit::CancellationToken;without a directtokio-utildependency. SeeCommand::cancel_on. A token which can be used to signal a cancellation request to one or more tasks. - CliClient
- Owns a CLI tool’s program name,
ProcessRunner, and default timeout, and builds + runsCommands against them. - Command
- A description of a child process to launch: program, arguments, working directory, environment, stdin source, and an optional timeout.
- Encoding
- An encoding as defined in the Encoding Standard.
- Invocation
- A captured record of one command a runner was asked to run.
- JobRunner
- The default runner: every run gets a fresh, private
ProcessGroupowned by the run, so its tree is torn down when the run finishes (or its handle drops). - Mock
Runner mock - The
mockall-generated mock ofProcessRunner(enabled by themockfeature), re-exported under a friendlier name. Runs aCommand— to a captured result (output) or a live handle (start). - Output
Buffer Policy - Caps how many captured/streamed output lines are retained in memory.
- Pipeline
- A chain of
Commands connected stdout→stdin — built withCommand::pipe, extended withpipe, driven withoutput_string/run. - Process
Group - A container that ties the lifetime of a child-process tree to its own.
- Process
Group Options - Tuning for a
ProcessGroup— graceful-shutdown timing and (with thelimitsfeature) resource limits. - Process
Group Stats stats - A snapshot of a process group’s resource usage.
- Process
Result - The captured result of running a process to completion.
- Process
Stdin - An interactive writer to a child’s standard input.
- Record
Replay Runner record - A
ProcessRunnerthat records real runs to a JSON cassette, or replays a cassette hermetically (recordfeature). - Recording
Runner - Wraps another
ProcessRunner, recording everyInvocationbefore delegating, so tests can assert exactly what was run. - Reply
- A canned reply: stdout/stderr text plus an exit code (or a timed-out run, or a parked-until-cancelled call).
- Resource
Limits limits - Resource limits enforced on a process group as a whole.
- RunProfile
stats - Resource summary of one finished run — produced by
RunningProcess::profile. - Running
Process - A handle to a process spawned by a runner.
- Scripted
Runner - A
ProcessRunnerthat returns cannedReplys for matched commands. - Stats
Sampler stats - A periodic
ProcessGroupStatsseries — created byProcessGroup::sample_stats. - Stdin
- What to feed a child process on standard input.
- Stdout
Lines - A
Streamof the child’s standard-output lines (seeRunningProcess::stdout_lines). - Supervision
Outcome - What a finished supervision reports — the last run plus the keeper’s telemetry.
- Supervisor
- Keeps a
Commandalive: runs it, classifies every exit against theRestartPolicyand thestop_whenpredicate, and restarts it after an exponential-backoff delay until supervision ends.
Enums§
- Error
- Errors produced when launching or running a child process.
- Mechanism
- The containment mechanism actually in effect for a process group.
- Outcome
- How a run ended — the explicit form of the
code()/timed_out()pair. - Overflow
Mode - What to drop when a bounded output buffer is full.
- Restart
Policy - When the supervisor restarts an exited child. See each variant; in every
case
stop_whenandmax_restartscan end supervision first. - Signal
process-control - A signal to broadcast to every process in a
ProcessGroupviasignal. - Stop
Reason - Why supervision ended.
Traits§
- Process
Runner - Runs a
Command— to a captured result (output) or a live handle (start). - Process
Runner Ext - Convenience methods available on every
ProcessRunner(including&dyn ProcessRunner), layered overoutput. - Stream
Ext - An extension trait for the
Streamtrait that provides a variety of convenient combinator functions.
Functions§
- output
- Run
programwithargsinside a private job and capture the result without erroring on a non-zero exit — for commands whose exit code is meaningful. - output_
all - Run every command in
commands, keeping at mostconcurrencyof them live at once, and collect all their results in input order. - run
- Run
programwithargsinside a private job and return trimmed stdout, or anErroron a non-zero exit / spawn failure / timeout. A thin shim overCommand; use the builder for a working directory, env, stdin, or timeout. - wait_
all - Wait for all of several running processes to exit, returning their exit
codes (
Nonefor a signal-killed run) in the same order asprocesses. - wait_
any - Wait for whichever of several running processes exits first, returning
its index in
processesand its exit code (Nonefor a signal-killed run, matchingRunningProcess::wait).
Type Aliases§
- Result
- Crate result alias.