3 unstable releases
0.2.1 | Dec 31, 2024 |
---|---|
0.2.0 | Sep 14, 2024 |
0.1.0 | Sep 9, 2024 |
#316 in Concurrency
140 downloads per month
Used in pidtree_mon
27KB
309 lines
with_daemon
- An async client-daemon abstraction framework
This crate abstracts away the spawning of and connecting to a daemon required to optimize tasks performed by multiple client instances that run in separate processes.
The daemon runs in a separate detached process from the first time the client is used and provides functionality to multiple instances of the client, taking advantage of the ability to have a common state shared between client handlers.
Usage
See an example from examples/counter.rs
:
//! `with_daemon` example: a simple global counter
//!
//! This example demonstrates how to use `with_daemon` in the most basic way.
//!
//! The daemon keeps track of a counter and each call to the client returns the current counter
//! value and increments the counter.
//!
//! When the compiled binary is executed, it spawns the daemon if it's not running yet, and
//! receives the current value from the daemon. This way each execution of the program provides a
//! different integer, until the daemon is manually killed.
use std::{
error::Error,
sync::atomic::{AtomicU32, Ordering},
};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use with_daemon::with_daemon;
fn main() -> Result<(), Box<dyn Error>> {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("off")).init();
let result = with_daemon(
"/tmp/with_daemon__example_counter.pid",
"/tmp/with_daemon__example_counter.sock",
// In this example the state is just an integer starting from 0.
//
// `with_daemon` expects an async function that returns the initial value of the state here.
// It awaits that function in the daemon process and passes the `Ok` result to each handler.
//
// The init function is fallible, and returning `Err` causes `Error::StateFailed` to be
// returned from `with_daemon`.
|_| async { Result::<_, String>::Ok(AtomicU32::new(0)) },
// The handler is given an `Arc` holding the state described above and a stream connected
// bi-directionally to the client it is handling.
//
// Here, it increments the state atomically and writes the value back to the client.
|state, mut stream| async move {
let previous = state.fetch_add(1, Ordering::SeqCst);
let _ = stream.write_u32(previous).await;
},
// The client is given a stream connected bi-directionally to an instance of a handler.
//
// Here, it only needs to read the result sent to it by the handler.
|mut stream| async move { stream.read_u32().await },
)?; // An error above signifies an internal error in `with_daemon`, for example inability to fork,
// so in the example we just fail when that happens.
// `result` here is just what our client closure returns, so an I/O error reading from stream.
println!("result: {}", result?);
Ok(())
}
See all examples in examples/
.
Dependencies
~3–11MB
~115K SLoC