1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
//! # Supervision trees for async Rust, inspired by Erlang/OTP
//!
//! This crate provides a supervision tree implementation for async Rust,
//! inspired by Erlang/OTP. It provides a [`Supertree`] struct that can be used
//! to create a supervision tree, and a [`Worker`] trait that can be implemented
//! by workers that can be added to the supervision tree.
//!
//! This crate is designed to be used with async Rust and the
//! [Tokio](https://tokio.rs/) runtime, but it could theoretically be used with
//! other async runtimes as well.
//!
//! In its current state, this crate is considered experimental and should not
//! be used for production services, unless you are very excited about the idea
//! and would be willing to contribute to the development of the crate. Notably,
//! this crate lacks a lot of the features that are present in Erlang/OTP, such
//! as monitoring, tracing, and distributed messaging, although Tokio provides a
//! tracing and metrics system that could be used in conjunction with this crate
//! (it has just not been tested yet).
//!
//! For detailed examples, refer to the integration tests in the
//! [`tests`](https://github.com/brndnmtthws/supertrees/tree/main/tests)
//! directory.
//!
//! ## Features
//!
//! - **Supervision trees**: Create a supervision tree with a root supervisor
//! - **Workers**: Add workers to the supervision tree
//! - **Async workers**: Workers are async and can use async/await syntax
//! - **Process isolation**: The tree is constructed by forking processes,
//! providing additional isolation (_IPC not currently implemented_)
//! - **Hierarchical structure**: Create a hierarchy of workers and supervisors
//! - **Restart policies**: Define restart policies for workers
//! - **Backoff policies**: Define backoff policies for workers
//!
//! ## Comparison to Erlang/OTP
//!
//! - Unlike Erlang/OTP, this crate does not provide a distributed messaging.
//! Another crate (courtesy chez moi) to look at is
//! [genserver](https://crates.io/crates/genserver), however it does not
//! provide IPC.
//! - This crate does not provide monitoring or tracing, but Tokio itself
//! includes a tracing and metrics system that could be used in conjunction
//! with this crate.
//! - Erlang/OTP uses a preemptive green-threads scheduler, while this crate
//! uses the Tokio runtime, which is a cooperative multitasking runtime.
//! - Each separate supervisor within the tree is a separate thread, and there's
//! no shared memory or IPC between them (yet, PRs welcome). This is in
//! contrast to Erlang/OTP, which uses a shared-nothing architecture.
//! - Erlang/OTP is battle-tested and has been used in production for decades,
//! whereas this crate is not.
//! ## Example
//!
//! A basic example of using this crate to create a supervision tree with a root
//! supervisor, two sub-supervisors, and three workers:
//!
//! ```rust
//! use supertrees::{Restartable, Supertree, Worker};
//!
//! #[derive(Debug)]
//! struct MyWorker {
//! num: i32,
//! }
//!
//! impl MyWorker {
//! fn new(num: i32) -> Self {
//! Self { num }
//! }
//! }
//!
//! impl Worker for MyWorker {
//! // init() is called before the worker is started, and will be called
//! // after each subsequent restart, so it should be safe to call this
//! // repeatedly and any state that needs to be reset should be reset here.
//! fn init(
//! &self,
//! ) -> std::pin::Pin<Box<dyn std::future::Future<Output = ()> + Send + 'static>> {
//! let num = self.num;
//! Box::pin(async move {
//! println!("hi, I'm worker num={num} :)");
//! })
//! }
//! }
//!
//! // We must provide a restart and backoff policy for the worker, but we can
//! // use the default policies.
//! impl Restartable for MyWorker {}
//!
//! let root = Supertree::new()
//! .add_worker(MyWorker::new(1))
//! .add_supervisor(|s| {
//! s.add_worker(MyWorker::new(2))
//! .add_supervisor(|s| s.add_worker(MyWorker::new(3)))
//! });
//! dbg!(&root);
//!
//! // Now you can start the supervision tree, which will run forever.
//! // Uncomment the line below to run the supervision tree.
//! // root.start();
//! ```
pub use Supervisor;
pub use BackoffPolicy;
pub use ;
pub use Worker;
/// Represents a supertree, which is a supervision tree that contains a root
/// supervisor.
/// Represents a Supervision tree, which is a hierarchical structure used for
/// managing workers and supervisors.
///
/// The Supertree struct provides methods for creating a new Supertree,
/// configuring backoff and restart policies, running the Supertree, adding
/// workers and supervisors to the Supertree.