dynamic_add/
simple.rs

1//! A minimal, self-contained demo of `ProcessManager`.
2//!
3//! • Builds a manager.
4//! • Registers two workers **before** start-up.
5//! • Runs for three seconds.
6//! • Initiates a graceful shutdown.
7//!
8//! Build & run:
9//! ```bash
10//! cargo run --example simple
11//! ```
12
13use processmanager::*;
14use std::sync::Arc;
15use std::time::Duration;
16use tokio::time::{interval, sleep};
17
18/// A lightweight long-running component that emits a heartbeat.
19struct Worker {
20    id: usize,
21    guard: Arc<RuntimeGuard>,
22}
23
24impl Worker {
25    fn new(id: usize) -> Self {
26        Self {
27            id,
28            guard: Arc::new(RuntimeGuard::default()),
29        }
30    }
31}
32
33impl Runnable for Worker {
34    fn process_start(&self) -> ProcFuture<'_> {
35        let id = self.id;
36        let guard = self.guard.clone();
37
38        Box::pin(async move {
39            let ticker = guard.runtime_ticker().await;
40            let mut tic = interval(Duration::from_secs(1));
41
42            loop {
43                match ticker.tick(tic.tick()).await {
44                    ProcessOperation::Next(_) => {
45                        println!("worker-{id}: heartbeat");
46                    }
47                    ProcessOperation::Control(RuntimeControlMessage::Reload) => {
48                        println!("worker-{id}: received *reload*");
49                    }
50                    ProcessOperation::Control(RuntimeControlMessage::Shutdown) => {
51                        println!("worker-{id}: shutting down");
52                        break;
53                    }
54                    // absorb any future control messages we don't explicitly handle
55                    ProcessOperation::Control(_) => continue,
56                }
57            }
58            Ok(())
59        })
60    }
61
62    fn process_handle(&self) -> Arc<dyn ProcessControlHandler> {
63        self.guard.handle()
64    }
65}
66
67#[tokio::main]
68async fn main() {
69    // -----------------------------------------------------------
70    // 1. Build a manager and register two workers
71    // -----------------------------------------------------------
72    let manager = ProcessManagerBuilder::default()
73        .pre_insert(Worker::new(0))
74        .pre_insert(Worker::new(1))
75        .build();
76
77    let handle = manager.process_handle();
78
79    // Spawn the supervisor; it will oversee both workers.
80    tokio::spawn(async move {
81        manager
82            .process_start()
83            .await
84            .expect("manager encountered an error");
85    });
86
87    // -----------------------------------------------------------
88    // 2. Let the system run for a short while
89    // -----------------------------------------------------------
90    println!("==> main: sleeping 3 s");
91    sleep(Duration::from_secs(3)).await;
92
93    // -----------------------------------------------------------
94    // 3. Graceful shutdown
95    // -----------------------------------------------------------
96    println!("==> main: initiating graceful shutdown");
97    handle.shutdown().await;
98
99    // Give children time to print their exit messages
100    sleep(Duration::from_secs(1)).await;
101}