psup_impl/
lib.rs

1#![deny(missing_docs)]
2//! Process supervisor with inter-process communication support using tokio.
3//!
4//! Currently only supports Unix, later we plan to add support for Windows using named pipes.
5//!
6//! ## Supervisor
7//!
8//! Supervisor manages child processes sending socket information using the environment and then switching
9//! to Unix domain sockets for inter-process communication. Daemon processes are restarted if
10//! they die without being shutdown by the supervisor.
11//!
12//! ```no_run
13//! use psup_impl::{Error, Result, Task, SupervisorBuilder};
14//!
15//! #[tokio::main]
16//! async fn main() -> Result<()> {
17//!    let worker_cmd = "worker-process";
18//!    let mut supervisor = SupervisorBuilder::new()
19//!        .server(|stream, tx| {
20//!             let (reader, mut writer) = stream.into_split();
21//!             tokio::task::spawn(async move {
22//!                 // Handle worker connection here
23//!                 // Use the `tx` supervisor control channel
24//!                 // to spawn and shutdown workers
25//!                 Ok::<(), Error>(())
26//!             });
27//!        })
28//!        .path(std::env::temp_dir().join("supervisor.sock"))
29//!        .add_worker(Task::new(worker_cmd).daemon(true))
30//!        .add_worker(Task::new(worker_cmd).daemon(true))
31//!        .build();
32//!    supervisor.run().await?;
33//!    // Block the process here and do your work.
34//!    Ok(())
35//! }
36//! ```
37//!
38//! ## Worker
39//!
40//! Worker reads the socket information from the environment and then connects to the Unix socket.
41//!
42//! ```no_run
43//! use psup_impl::{Error, Result, Worker};
44//!
45//! #[tokio::main]
46//! async fn main() -> Result<()> {
47//!     // Read supervisor information from the environment
48//!     // and set up the IPC channel with the supervisor
49//!     let worker = Worker::new()
50//!         .client(|stream, id| async {
51//!             let (reader, mut writer) = stream.into_split();
52//!             // Start sending messages to the supervisor
53//!             Ok::<(), Error>(())
54//!         });
55//!     worker.run().await?;
56//!     // Block the process here and do your work.
57//!     Ok(())
58//! }
59//! ```
60
61/// Enumeration of errors.
62#[derive(Debug, thiserror::Error)]
63pub enum Error {
64    /// Worker is missing the id environment variable.
65    #[error("Worker PSUP_WORKER_ID variable is not set")]
66    WorkerNoId,
67
68    /// Input/output errors.
69    #[error(transparent)]
70    Io(#[from] std::io::Error),
71
72    /// Error whilst sending bind notifications.
73    #[error(transparent)]
74    Oneshot(#[from] tokio::sync::oneshot::error::RecvError),
75
76    /// Generic variant for errors created in user code.
77    #[error(transparent)]
78    Boxed(#[from] Box<dyn std::error::Error + Send + Sync>),
79}
80
81/// Result type returned by the library.
82pub type Result<T> = std::result::Result<T, Error>;
83
84pub(crate) const WORKER_ID: &str = "PSUP_WORKER_ID";
85pub(crate) const SOCKET: &str = "PSUP_SOCKET";
86
87mod supervisor;
88mod worker;
89
90pub use supervisor::{Message, Supervisor, SupervisorBuilder, Task, id};
91pub use worker::Worker;