| Crates.io | proc-heim |
| lib.rs | proc-heim |
| version | 0.1.5 |
| created_at | 2025-01-21 19:44:55.976639+00 |
| updated_at | 2025-04-07 17:04:08.797291+00 |
| description | Library for running and managing short-lived and long-lived processes using asynchronous API |
| homepage | |
| repository | https://github.com/Heliwrenaid/proc-heim |
| max_upload_size | |
| id | 1525282 |
| size | 202,058 |
Proc-heim is a library for running and managing short-lived and long-lived processes using asynchronous API. A new process can be created by running either command or script.
Proc-heim internally uses tokio::process for executing processes and provides all its functionality plus additional features:
Rust types, which implements Runnable trait,For more detailed list of features see ProcessManagerHandle documentation.
Proc-heim library is divided into two modules: model and manager.
The first one defines types and traits used to describe commands, scripts and their settings, such as messaging and logging type, environment variables and working directory. The module contains a Runnable trait, which defines how to run a user-defined process. The library provides two implementation of this trait: Cmd and Script.
The manager module provides an API for spawning and managing child processes. The whole implementation relies on Actor model architecture. To start using the library, a client code needs to spawn a ProcessManager task, responsible for:
After spawning the ProcessManager task, a ProcessManagerHandle is being returned, which exposes an API for spawning and managing user-defined processes.
ProcessManager taskuse proc_heim::manager::ProcessManager;
use std::path::PathBuf;
let working_directory = PathBuf::from("/some/temp/path");
let handle = ProcessManager::spawn(working_directory)?;
// now use the handle to spawn new processes and interact with them
use proc_heim::manager::ProcessManager;
use std::path::PathBuf;
let working_directory = PathBuf::from("/tmp/proc_heim");
let handle = ProcessManager::spawn(working_directory)?;
let cmd = Cmd::with_args("ls", ["-l", "/some/dir"]);
let process_id = handle.spawn(cmd).await?;
// now use the process_id to interact with a process ...
use proc_heim::{
manager::{LogsQuery, ProcessManager},
model::{
command::{CmdOptions, LoggingType},
script::{Script, ScriptingLanguage}
},
};
use std::{path::PathBuf, time::Duration};
let working_directory = PathBuf::from("/tmp/proc_heim");
let handle = ProcessManager::spawn(working_directory)?;
let script = Script::with_args_and_options(
ScriptingLanguage::Bash,
r#"
echo 'Simple log example'
echo "Hello $1"
echo 'Error log' >&2
"#,
["World"],
CmdOptions::with_logging(LoggingType::StdoutAndStderr),
);
let process_id = handle.spawn(script).await?;
// We are waiting for the process to exit in order to get all logs
handle.wait(process_id, Duration::from_micros(10)).await??;
let logs = handle
.get_logs_stdout(process_id, LogsQuery::with_offset(1))
.await?;
assert_eq!(1, logs.len());
assert_eq!("Hello World", logs[0]);
let error_logs = handle
.get_logs_stderr(process_id, LogsQuery::fetch_all())
.await?;
assert_eq!(1, error_logs.len());
assert_eq!("Error log", error_logs[0]);
use futures::TryStreamExt;
use proc_heim::{
manager::ProcessManager,
model::{
command::CmdOptions,
script::{Script, ScriptingLanguage},
},
};
use std::path::PathBuf;
let working_directory = PathBuf::from("/tmp/proc_heim");
let handle = ProcessManager::spawn(working_directory)?;
let script = Script::with_options(
ScriptingLanguage::Bash,
r#"
counter=0
while read msg; do
echo "$counter: $msg" > $OUTPUT_PIPE
counter=$((counter + 1))
done < $INPUT_PIPE
"#,
CmdOptions::with_named_pipe_messaging(), // we want to send messages bidirectionally
);
// We can use "spawn_with_handle" instead of "spawn" to get "ProcessHandle",
// which mimics the "ProcessManagerHandle" API,
// but without having to pass the process ID to each method call.
let process_handle = handle.spawn_with_handle(script).await?;
process_handle.send_message("First message").await?;
// We can send a next message without causing a deadlock here.
// This is possible because the response to the first message
// will be read by a dedicated Tokio task,
// spawned automatically by the Process Manager.
process_handle.send_message("Second message").await?;
let mut stream = process_handle.subscribe_message_string_stream().await?;
let msg = stream.try_next().await?.unwrap();
assert_eq!("0: First message", msg);
let msg = stream.try_next().await?.unwrap();
assert_eq!("1: Second message", msg);
let result = process_handle.kill().await;
assert!(result.is_ok());
For more examples, see integration tests.