Skip to main content

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}