supervisor_tree_story/supervisor_tree_story.rs
1//! Demonstrates a multi-child supervisor tree declaration and traversal.
2
3// Import child identifiers.
4use rust_supervisor::id::types::ChildId;
5// Import readiness policy values.
6use rust_supervisor::readiness::signal::ReadinessPolicy;
7// Import child specification values.
8use rust_supervisor::spec::child::{ChildSpec, Criticality, TaskKind};
9// Import supervisor specification values.
10use rust_supervisor::spec::supervisor::{SupervisionStrategy, SupervisorSpec};
11// Import task factory helpers.
12use rust_supervisor::task::factory::{TaskResult, service_fn};
13// Import supervisor tree builder.
14use rust_supervisor::tree::builder::SupervisorTree;
15// Import tree ordering helpers.
16use rust_supervisor::tree::order::{restart_scope, shutdown_order, startup_order};
17// Import shared ownership for task factories.
18use std::sync::Arc;
19
20// Define the shared example result type.
21type ExampleResult = Result<(), rust_supervisor::error::types::SupervisorError>;
22
23// Run the supervisor tree declaration example.
24/// Runs the supervisor tree declaration example.
25fn main() -> ExampleResult {
26 // Build the market feed child.
27 let mut market_feed = worker("market_feed", "Market Feed");
28 // Add low-cardinality market feed tags.
29 market_feed.tags = vec!["market".to_owned(), "network".to_owned()];
30 // Require explicit readiness for the market feed.
31 market_feed.readiness_policy = ReadinessPolicy::Explicit;
32
33 // Build the risk engine child.
34 let mut risk_engine = worker("risk_engine", "Risk Engine");
35 // Make the risk engine depend on the market feed.
36 risk_engine.dependencies = vec![market_feed.id.clone()];
37 // Add low-cardinality risk engine tags.
38 risk_engine.tags = vec!["risk".to_owned()];
39
40 // Build the audit sink child.
41 let mut audit_sink = worker("audit_sink", "Audit Sink");
42 // Mark the audit sink as optional.
43 audit_sink.criticality = Criticality::Optional;
44 // Add low-cardinality audit tags.
45 audit_sink.tags = vec!["audit".to_owned()];
46
47 // Build the root supervisor specification.
48 let mut spec = SupervisorSpec::root(vec![market_feed.clone(), risk_engine, audit_sink]);
49 // Select the RestForOne restart strategy.
50 spec.strategy = SupervisionStrategy::RestForOne;
51 // Set an example configuration version.
52 spec.config_version = "examples-supervisor-tree-story".to_owned();
53
54 // Build the indexed supervisor tree.
55 let tree = SupervisorTree::build(&spec)?;
56 // Print the root supervisor path.
57 println!("root_path={}", tree.root_path);
58 // Print startup order by child name.
59 println!("startup_order={:?}", child_names(startup_order(&tree)));
60 // Print shutdown order by child name.
61 println!("shutdown_order={:?}", child_names(shutdown_order(&tree)));
62 // Print the restart scope after market feed failure.
63 println!(
64 // Provide the output template.
65 "restart_scope_after_market_feed={:?}",
66 // Calculate the restart scope.
67 restart_scope(&tree, spec.strategy, &market_feed.id),
68 // Finish printing the restart scope.
69 );
70
71 // Finish the example successfully.
72 Ok(())
73 // End the supervisor tree example.
74}
75
76// Build a worker child specification.
77/// Builds one worker child specification.
78fn worker(id: &str, name: &str) -> ChildSpec {
79 // Capture the task name for the async task.
80 let task_name = name.to_owned();
81 // Create a task factory from a closure.
82 let factory = service_fn(move |ctx| {
83 // Clone the captured task name for this attempt.
84 let task_name = task_name.clone();
85 // Return the async task body.
86 async move {
87 // Emit a heartbeat from the task context.
88 ctx.heartbeat();
89 // Mark the task as ready.
90 ctx.mark_ready();
91 // Print the task path for learners.
92 println!("worker={task_name} path={}", ctx.path);
93 // Report a successful task result.
94 TaskResult::Succeeded
95 // Finish the async task body.
96 }
97 // Finish the task factory closure.
98 });
99
100 // Create the worker child specification.
101 ChildSpec::worker(
102 // Set the child identifier.
103 ChildId::new(id),
104 // Set the child name.
105 name,
106 // Set the task kind.
107 TaskKind::AsyncWorker,
108 // Store the task factory behind shared ownership.
109 Arc::new(factory),
110 // Finish the worker child specification.
111 )
112 // Finish the worker builder.
113}
114
115// Collect child names from tree nodes.
116/// Collects child names from tree nodes.
117fn child_names(nodes: Vec<&rust_supervisor::tree::builder::SupervisorTreeNode>) -> Vec<String> {
118 // Convert node references into owned child names.
119 nodes
120 // Consume the node vector.
121 .into_iter()
122 // Clone each child name.
123 .map(|node| node.child.name.clone())
124 // Collect the names into a vector.
125 .collect()
126 // Finish collecting child names.
127}