Process & ProcessId
ProcessId
A unique identifier assigned by ProcessManager to each spawned process. Implemented as a u64 newtype.
ProcessId is generated atomically from an internal counter in ProcessManager. It is unique within a single ProcessManager instance - no two processes will share the same ProcessId.
Trait Implementations
Display- formats as a numberPartialEq,Eq,Hash- comparison and hashingClone,Copy- lightweight value type
Usage
#![allow(unused)]
fn main() {
// ProcessId is returned by start()
let id = manager.start("task", &config)?;
// Used for stop(), get(), etc.
manager.stop(id)?;
let process = manager.get(id);
}
Process
A handle to a managed child process. Stored in ProcessManager’s DashMap and accessed via get_info() which returns a ProcessInfo snapshot.
Lifecycle
graph TD
classDef default fill: #1e1e1e, stroke: #333333, stroke-width: 1px, color: #ffffff
classDef start fill: #89fc00, stroke: #333333, stroke-width: 2px, color: #000
classDef running fill: #00a1e4, stroke: #ffffff, stroke-width: 2px, color: #ffffff
classDef signal fill: #f5b700, stroke: #333333, stroke-width: 2px, color: #000000
classDef stop fill: #dc0073, stroke: #333333, stroke-width: 2px, color: #ffffff
classDef done fill: #04e762, stroke: #333333, stroke-width: 1px, color: #000
classDef failed fill: #dc0073, stroke: #333333, stroke-width: 1px, color: #ffffff
A["start()"] --> B["Starting<br/>transient"]
B --> C["Running<br/>in DashMap"]
B -->|"spawn fails"| F["Failed"]
C -->|"send_signal()"| C
C -->|"stop()"| D["Stopping<br/>SIGTERM sent"]
C -->|"restart()"| G["Restarting"]
C -->|"process exits<br/>(reaper detects)"| E["ProcessExitEvent"]
D -->|"exits normally"| H["Stopped"]
D -->|"exits with error"| I["Crashed"]
G -->|"stop old, start new"| B
E --> E2["Removed from<br/>DashMap"]
H --> E2
I --> E2
F --> E2
class A start
class B running
class C running
class D stop
class E signal
class E2 done
class F failed
class G signal
class H done
class I done
Fields
| Field | Type | Description |
|---|---|---|
id | ProcessId | Unique identifier assigned by ProcessManager |
pid | u32 | OS process ID |
program_name | String | Program name (for error reporting) |
label | Label | Label under which the process was started |
terminate_on_exit | bool | Whether to terminate on ProcessManager drop |
config | ProcessConfig | The configuration this process was started with |
child | Option<Child> | The std::process::Child handle (always Some) |
state | ProcessState | The current lifecycle state (updated lazily by state(), explicitly by stop() / restart()) |
Methods
| Method | Returns | Description |
|---|---|---|
is_running() | bool | Non-blocking check via try_wait() - true if still running (delegates to state().is_alive()) |
state() | ProcessState | Non-blocking check via try_wait() - returns the current lifecycle state, updating it if the process has exited |
send_signal(signal) | Result<(), nix::Error> | Send a signal to the process via nix::sys::signal::kill |
force_kill() | Result<(), nix::Error> | Send SIGKILL immediately |
Clone Behavior
Process implements Clone manually because std::process::Child does not implement Clone. The clone shares the PID and config but does not duplicate the Child handle - the clone’s child field is None. This is sufficient for read-only access patterns (checking is_running(), reading PID/label).
Usage
#![allow(unused)]
fn main() {
let id = manager.start("task", &config)?;
// Access via DashMap guard
let process = manager.get(id).unwrap();
println!("PID: {}, Label: {}", process.pid, process.label);
println!("Running: {}", process.is_running());
println!("State: {}", process.state);
drop(process); // Release DashMap guard
// Stop the process
manager.stop(id)?;
}