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
//! Where you have services, you need managers

use crate::service::Service;
use crate::utils;

use log::*;

/// Manages an internal collection of Services
///
/// This implements a simple [Composite Pattern](https://en.wikipedia.org/wiki/Composite_pattern)
/// that allows to manages a group of Service in a coordinated fashion.
///
/// Services are `start()`ed in the order they are registered, and `stop()`ped in the reverse
/// order. Also, a `ServiceManager` is also a `Service`, so further composition is possible.
///
/// The design implies that in your application, you would hand over all the instances of `Service`
/// to a `ServiceManager`, that will then orchestrate their starting and stopping.
///
/// Thanks to the use of Composite Pattern, it can contain further instances of `ServiceManager`,
/// allowing for the creation of complex
/// [DAG diagrams](https://en.wikipedia.org/wiki/Directed_acyclic_graph) of services,
/// with expressive relationship between them.
pub struct ServiceManager {
  services: Vec<Box<Service>>
}

impl ServiceManager {

  /// Constructor
  pub fn new() -> Self {
    ServiceManager {
      services: Vec::new(),
    }
  }

  /// Register an instance of `Service`.
  ///
  /// The order of registration is important: `Service`s are started in order, and stopped
  /// in reverse order.
  ///
  /// # Parameters
  ///
  /// * `service_box`: a `Box` containing an instance of implementation of the `Service` trait
  pub fn register(&mut self, service_box: Box<Service>) {
    debug!("Registering: {}", service_box.as_ref().name());
    self.services.push(service_box);
  }

  /// Wait for the Process to receive a termination signal, then stop this `ServiceManager`.
  ///
  /// It's strongly advised to use this method only onces, for the _root_ `ServiceManager`,
  /// at the end of the `main()` thread.
  pub fn await_termination_signal_then_stop(&mut self) {
    // Block until the process is terminated by a signal...
    utils::await_for_process_termination_signal();

    // ... then gracefully shut every service down
    self.stop_and_await();
  }

  /// Apply the same closure to all contained `Service`s, in order
  fn apply_ordered<F>(&mut self, closure: F) where F: Fn(&mut Box<Service>) -> () {
    self.services
      .iter_mut()
      .for_each(closure);
  }

  /// Apply the same closure to all contained `Service`s, in reverse order
  fn apply_reversed<F>(&mut self, closure: F) where F: FnMut(&mut Box<Service>) -> () {
    self.services
      .iter_mut()
      .rev()
      .for_each(closure);
  }

}

const SERVICE_MANAGER_SERVICE_NAME: &'static str = "srvzio::ServiceManager";

impl Service for ServiceManager {

  fn name(&self) -> &'static str {
    SERVICE_MANAGER_SERVICE_NAME
  }

  /// Start all registered `Service`s, in order of registration
  fn start(&mut self) {
    self.apply_ordered(|s: &mut Box<Service>| {
      debug!("Starting: {}", s.name());
      s.start()
    });
  }

  /// Wait for all registered `Service`s to be started, in order of registration
  fn await_started(&mut self) {
    self.apply_ordered(|s: &mut Box<Service>| {
      debug!("Awaiting started: {}", s.name());
      s.await_started()
    });
  }

  /// Start and then wait for all registered `Service`, in order of registration
  ///
  /// This is different then calling `start()` and then `await_started()`, because this method
  /// will wait for a `Service` to be started, before moving to the next one.
  ///
  /// This can be used to implement a _gracefull start_.
  fn start_and_await(&mut self) {
    self.apply_ordered(|s: &mut Box<Service>| s.start_and_await());
  }


  /// Stop all registered `Service`s, in reverse order of registration
  fn stop(&mut self) {
    self.apply_reversed(|s: &mut Box<Service>| {
      debug!("Stopping: {}", s.name());
      s.stop()
    });
  }

  /// Wait for all registered `Service`s to be stopped, in reverse order of registration
  fn await_stopped(&mut self) {
    self.apply_reversed(|s: &mut Box<Service>| {
      debug!("Awaiting stopped: {}", s.name());
      s.await_stopped()
    });
  }

  /// Stop and then wait for all registered `Service`, in reverse order of registration
  ///
  /// This is different then calling `stop()` and then `await_stopped()`, because this method
  /// will wait for a `Service` to be stopped, before moving to the next one.
  ///
  /// This can be used to implement a _gracefull stop_.
  fn stop_and_await(&mut self) {
    self.apply_reversed(|s: &mut Box<Service>| s.stop_and_await());
  }

}