mirror of https://github.com/bastion-rs/bastion
705 lines
21 KiB
Rust
705 lines
21 KiB
Rust
use crate::broadcast::{Broadcast, Parent};
|
|
use crate::children::Children;
|
|
use crate::children_ref::ChildrenRef;
|
|
use crate::config::Config;
|
|
use crate::context::{BastionContext, BastionId};
|
|
use crate::envelope::Envelope;
|
|
use crate::message::{BastionMessage, Message};
|
|
use crate::path::BastionPathElement;
|
|
use crate::supervisor::{Supervisor, SupervisorRef};
|
|
use crate::system::SYSTEM;
|
|
|
|
use core::future::Future;
|
|
use tracing::{debug, trace};
|
|
|
|
use std::fmt::{self, Debug, Formatter};
|
|
|
|
distributed_api! {
|
|
use std::sync::Arc;
|
|
use crate::distributed::*;
|
|
use artillery_core::cluster::ap::*;
|
|
}
|
|
|
|
/// A `struct` allowing to access the system's API to initialize it,
|
|
/// start, stop and kill it and to create new supervisors and top-level
|
|
/// children groups.
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```rust
|
|
/// use bastion::prelude::*;
|
|
///
|
|
/// # #[cfg(feature = "tokio-runtime")]
|
|
/// # #[tokio::main]
|
|
/// # async fn main() {
|
|
/// # run();
|
|
/// # }
|
|
/// #
|
|
/// # #[cfg(not(feature = "tokio-runtime"))]
|
|
/// # fn main() {
|
|
/// # run();
|
|
/// # }
|
|
/// #
|
|
/// fn run() {
|
|
/// /// Creating the system's configuration...
|
|
/// let config = Config::new().hide_backtraces();
|
|
/// // ...and initializing the system with it (this is required)...
|
|
/// Bastion::init_with(config);
|
|
///
|
|
/// // Note that `Bastion::init();` would work too and initialize
|
|
/// // the system with the default config.
|
|
///
|
|
/// // Starting the system...
|
|
/// Bastion::start();
|
|
///
|
|
/// // Creating a new supervisor...
|
|
/// let supervisor = Bastion::supervisor(|sp| {
|
|
/// sp
|
|
/// // ...with a specific supervision strategy...
|
|
/// .with_strategy(SupervisionStrategy::OneForAll)
|
|
/// // ...and some supervised children groups...
|
|
/// .children(|children| {
|
|
/// // ...
|
|
/// # children
|
|
/// })
|
|
/// .children(|children| {
|
|
/// // ...
|
|
/// # children
|
|
/// })
|
|
/// // ...or even supervised supervisors...
|
|
/// .supervisor(|sp| {
|
|
/// // ...
|
|
/// # sp
|
|
/// })
|
|
/// }).expect("Couldn't create the supervisor.");
|
|
///
|
|
/// // ...which can start supervising new children groups
|
|
/// // later on...
|
|
/// supervisor.children(|children| {
|
|
/// // ...
|
|
/// # children
|
|
/// }).expect("Couldn't create the supervised children group.");
|
|
///
|
|
/// // ...or broadcast messages to all its supervised children
|
|
/// // and supervisors...
|
|
/// supervisor.broadcast("A message containing data.").expect("Couldn't broadcast the message.");
|
|
///
|
|
/// // ...and then can even be stopped or killed...
|
|
/// supervisor.stop().expect("Couldn't stop the supervisor");
|
|
/// // supervisor.kill().expect("Couldn't kill the supervisor");
|
|
///
|
|
/// // Creating a new top-level children group...
|
|
/// let children = Bastion::children(|children| {
|
|
/// children
|
|
/// // ...containing a defined number of elements...
|
|
/// .with_redundancy(4)
|
|
/// // ...all executing a similar future...
|
|
/// .with_exec(|ctx: BastionContext| {
|
|
/// async move {
|
|
/// // ...receiving and matching messages...
|
|
/// msg! { ctx.recv().await?,
|
|
/// ref msg: &'static str => {
|
|
/// // ...
|
|
/// };
|
|
/// msg: &'static str => {
|
|
/// // ...
|
|
/// };
|
|
/// msg: &'static str =!> {
|
|
/// // ...
|
|
/// };
|
|
/// // ...
|
|
/// _: _ => ();
|
|
/// }
|
|
///
|
|
/// // ...
|
|
///
|
|
/// Ok(())
|
|
/// }
|
|
/// })
|
|
/// }).expect("Couldn't create the children group.");
|
|
///
|
|
/// // ...which can broadcast messages to all its elements...
|
|
/// children.broadcast("A message containing data.").expect("Couldn't broadcast the message.");
|
|
///
|
|
/// // ...and then can even be stopped or killed...
|
|
/// children.stop().expect("Couldn't stop the children group.");
|
|
/// // children.kill().expect("Couldn't kill the children group.");
|
|
///
|
|
/// // Create a new top-level children group and getting a list
|
|
/// // of reference to its elements...
|
|
/// let children = Bastion::children(|children| {
|
|
/// // ...
|
|
/// # children.with_exec(|ctx: BastionContext| {
|
|
/// # async move {
|
|
/// # msg! { ctx.recv().await?,
|
|
/// # _: _ => ();
|
|
/// # }
|
|
/// # Ok(())
|
|
/// # }
|
|
/// # })
|
|
/// }).expect("Couldn't create the children group.");
|
|
/// let elems: &[ChildRef] = children.elems();
|
|
///
|
|
/// // ...to then get one of its elements' reference...
|
|
/// let child = &elems[0];
|
|
///
|
|
/// // ...to then "tell" it messages...
|
|
/// child.tell_anonymously("A message containing data.").expect("Couldn't send the message.");
|
|
///
|
|
/// // ...or "ask" it messages...
|
|
/// let answer: Answer = child.ask_anonymously("A message containing data.").expect("Couldn't send the message.");
|
|
/// # async {
|
|
/// // ...until the child eventually answers back...
|
|
/// let answer: Result<SignedMessage, ()> = run!(answer);
|
|
/// # };
|
|
///
|
|
/// // ...and then even stop or kill it...
|
|
/// child.stop().expect("Couldn't stop the child.");
|
|
/// // child.kill().expect("Couldn't kill the child.");
|
|
///
|
|
/// // Broadcasting a message to all the system's children...
|
|
/// Bastion::broadcast("A message containing data.").expect("Couldn't send the message.");
|
|
///
|
|
/// // Stopping or killing the system...
|
|
/// Bastion::stop();
|
|
/// // Bastion::kill();
|
|
///
|
|
/// // Blocking until the system has stopped (or got killed)...
|
|
/// Bastion::block_until_stopped();
|
|
/// }
|
|
/// ```
|
|
pub struct Bastion {
|
|
_priv: (),
|
|
}
|
|
|
|
impl Bastion {
|
|
/// Initializes the system if it hasn't already been done, using
|
|
/// the default [`Config`].
|
|
///
|
|
/// **It is required that you call `Bastion::init` or
|
|
/// [`Bastion::init_with`] at least once before using any of
|
|
/// bastion's features.**
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```rust
|
|
/// # #[cfg(feature = "tokio-runtime")]
|
|
/// # #[tokio::main]
|
|
/// # async fn main() {
|
|
/// # run();
|
|
/// # }
|
|
/// #
|
|
/// # #[cfg(not(feature = "tokio-runtime"))]
|
|
/// # fn main() {
|
|
/// # run();
|
|
/// # }
|
|
/// #
|
|
/// # fn run() {
|
|
/// use bastion::prelude::*;
|
|
///
|
|
/// Bastion::init();
|
|
///
|
|
/// // You can now use bastion...
|
|
/// #
|
|
/// # Bastion::start();
|
|
/// # Bastion::stop();
|
|
/// # Bastion::block_until_stopped();
|
|
/// # }
|
|
/// ```
|
|
pub fn init() {
|
|
let config = Config::default();
|
|
Bastion::init_with(config)
|
|
}
|
|
|
|
/// Initializes the system if it hasn't already been done, using
|
|
/// the specified [`Config`].
|
|
///
|
|
/// **It is required that you call [`Bastion::init`] or
|
|
/// `Bastion::init_with` at least once before using any of
|
|
/// bastion's features.**
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `config` - The configuration used to initialize the system.
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```rust
|
|
/// use bastion::prelude::*;
|
|
///
|
|
/// # #[cfg(feature = "tokio-runtime")]
|
|
/// # #[tokio::main]
|
|
/// # async fn main() {
|
|
/// # run();
|
|
/// # }
|
|
/// #
|
|
/// # #[cfg(not(feature = "tokio-runtime"))]
|
|
/// # fn main() {
|
|
/// # run();
|
|
/// # }
|
|
/// #
|
|
/// # fn run() {
|
|
/// let config = Config::new()
|
|
/// .show_backtraces();
|
|
///
|
|
/// Bastion::init_with(config);
|
|
///
|
|
/// // You can now use bastion...
|
|
/// #
|
|
/// # Bastion::start();
|
|
/// # Bastion::stop();
|
|
/// # Bastion::block_until_stopped();
|
|
/// # }
|
|
/// ```
|
|
pub fn init_with(config: Config) {
|
|
debug!("Bastion: Initializing with config: {:?}", config);
|
|
if config.backtraces().is_hide() {
|
|
debug!("Bastion: Hiding backtraces.");
|
|
std::panic::set_hook(Box::new(|_| ()));
|
|
}
|
|
|
|
let _ = &SYSTEM;
|
|
}
|
|
|
|
/// Creates a new [`Supervisor`], passes it through the specified
|
|
/// `init` closure and then sends it to the system for it to
|
|
/// start supervising children.
|
|
///
|
|
/// This method returns a [`SupervisorRef`] referencing the newly
|
|
/// created supervisor if it succeeded, or `Err(())`
|
|
/// otherwise.
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `init` - The closure taking the new [`Supervisor`] as an
|
|
/// argument and returning it once configured.
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```rust
|
|
/// # use bastion::prelude::*;
|
|
/// #
|
|
/// # #[cfg(feature = "tokio-runtime")]
|
|
/// # #[tokio::main]
|
|
/// # async fn main() {
|
|
/// # run();
|
|
/// # }
|
|
/// #
|
|
/// # #[cfg(not(feature = "tokio-runtime"))]
|
|
/// # fn main() {
|
|
/// # run();
|
|
/// # }
|
|
/// #
|
|
/// # fn run() {
|
|
/// # Bastion::init();
|
|
/// #
|
|
/// let sp_ref: SupervisorRef = Bastion::supervisor(|sp| {
|
|
/// // Configure the supervisor...
|
|
/// sp.with_strategy(SupervisionStrategy::OneForOne)
|
|
/// // ...and return it.
|
|
/// }).expect("Couldn't create the supervisor.");
|
|
/// #
|
|
/// # Bastion::start();
|
|
/// # Bastion::stop();
|
|
/// # Bastion::block_until_stopped();
|
|
/// # }
|
|
/// ```
|
|
pub fn supervisor<S>(init: S) -> Result<SupervisorRef, ()>
|
|
where
|
|
S: FnOnce(Supervisor) -> Supervisor,
|
|
{
|
|
debug!("Bastion: Creating supervisor.");
|
|
let parent = Parent::system();
|
|
let bcast = Broadcast::new(parent, BastionPathElement::Supervisor(BastionId::new()));
|
|
|
|
debug!("Bastion: Initializing Supervisor({}).", bcast.id());
|
|
let supervisor = Supervisor::new(bcast);
|
|
let supervisor = init(supervisor);
|
|
debug!("Supervisor({}): Initialized.", supervisor.id());
|
|
let supervisor_ref = supervisor.as_ref();
|
|
|
|
debug!("Bastion: Deploying Supervisor({}).", supervisor.id());
|
|
let msg = BastionMessage::deploy_supervisor(supervisor);
|
|
let envelope = Envelope::new(msg, SYSTEM.path().clone(), SYSTEM.sender().clone());
|
|
trace!("Bastion: Sending envelope: {:?}", envelope);
|
|
SYSTEM.sender().unbounded_send(envelope).map_err(|_| ())?;
|
|
|
|
Ok(supervisor_ref)
|
|
}
|
|
|
|
/// Creates a new [`Children`], passes it through the specified
|
|
/// `init` closure and then sends it to the system's default
|
|
/// supervisor for it to start supervising it.
|
|
///
|
|
/// This methods returns a [`ChildrenRef`] referencing the newly
|
|
/// created children group it it succeeded, or `Err(())`
|
|
/// otherwise.
|
|
///
|
|
/// Note that the "system supervisor" is a supervisor created
|
|
/// by the system at startup.
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `init` - The closure taking the new [`Children`] as an
|
|
/// argument and returning it once configured.
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```rust
|
|
/// # use bastion::prelude::*;
|
|
/// #
|
|
/// # #[cfg(feature = "tokio-runtime")]
|
|
/// # #[tokio::main]
|
|
/// # async fn main() {
|
|
/// # run();
|
|
/// # }
|
|
/// #
|
|
/// # #[cfg(not(feature = "tokio-runtime"))]
|
|
/// # fn main() {
|
|
/// # run();
|
|
/// # }
|
|
/// #
|
|
/// # fn run() {
|
|
/// # Bastion::init();
|
|
/// #
|
|
/// let children_ref: ChildrenRef = Bastion::children(|children| {
|
|
/// // Configure the children group...
|
|
/// children.with_exec(|ctx: BastionContext| {
|
|
/// async move {
|
|
/// // Send and receive messages...
|
|
/// let opt_msg: Option<SignedMessage> = ctx.try_recv().await;
|
|
/// // ...and return `Ok(())` or `Err(())` when you are done...
|
|
/// Ok(())
|
|
///
|
|
/// // Note that if `Err(())` was returned, the supervisor would
|
|
/// // restart the children group.
|
|
/// }
|
|
/// })
|
|
/// // ...and return it.
|
|
/// }).expect("Couldn't create the children group.");
|
|
/// #
|
|
/// # Bastion::start();
|
|
/// # Bastion::stop();
|
|
/// # Bastion::block_until_stopped();
|
|
/// # }
|
|
/// ```
|
|
pub fn children<C>(init: C) -> Result<ChildrenRef, ()>
|
|
where
|
|
C: FnOnce(Children) -> Children,
|
|
{
|
|
debug!("Bastion: Creating children group.");
|
|
SYSTEM.supervisor().children(init)
|
|
}
|
|
|
|
/// Creates a new [`Children`] which will have the given closure
|
|
/// as action and then sends it to the system's default supervisor.
|
|
///
|
|
/// This method returns a [`ChildrenRef`] referencing the newly created children
|
|
/// if the creation was successful, otherwise returns an `Err(())`.
|
|
///
|
|
/// Internally this method uses the [`Bastion::children`] and [`Children::with_exec`] methods
|
|
/// to create a new children.
|
|
///
|
|
/// # Arguments
|
|
/// * `action` - The closure which gets executed by the child.
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```rust
|
|
/// # use bastion::prelude::*;
|
|
/// #
|
|
/// # #[cfg(feature = "tokio-runtime")]
|
|
/// # #[tokio::main]
|
|
/// # async fn main() {
|
|
/// # run();
|
|
/// # }
|
|
/// #
|
|
/// # #[cfg(not(feature = "tokio-runtime"))]
|
|
/// # fn main() {
|
|
/// # run();
|
|
/// # }
|
|
/// #
|
|
/// # fn run() {
|
|
/// # Bastion::init();
|
|
/// #
|
|
/// let children_ref: ChildrenRef = Bastion::spawn(|ctx: BastionContext| {
|
|
/// async move {
|
|
/// // ...
|
|
/// Ok(())
|
|
/// }
|
|
/// }).expect("Couldn't create the children group.");
|
|
/// #
|
|
/// # Bastion::start();
|
|
/// # Bastion::stop();
|
|
/// # Bastion::block_until_stopped();
|
|
/// # }
|
|
/// ```
|
|
pub fn spawn<I, F>(action: I) -> Result<ChildrenRef, ()>
|
|
where
|
|
I: Fn(BastionContext) -> F + Send + 'static,
|
|
F: Future<Output = Result<(), ()>> + Send + 'static,
|
|
{
|
|
Bastion::children(|ch| ch.with_redundancy(1).with_exec(action))
|
|
}
|
|
distributed_api! {
|
|
// FIXME!
|
|
#[allow(missing_docs)]
|
|
pub fn distributed<I, F>(cluster_config: &'static ArtilleryAPClusterConfig, action: I) -> Result<ChildrenRef, ()>
|
|
where
|
|
I: Fn(Arc<DistributedContext>) -> F + Send + Sync + 'static,
|
|
F: Future<Output = Result<(), ()>> + Send + 'static,
|
|
{
|
|
cluster_actor(cluster_config, action)
|
|
}
|
|
}
|
|
|
|
/// Sends a message to the system which will then send it to all
|
|
/// the root-level supervisors and their supervised children and
|
|
/// supervisors, etc.
|
|
///
|
|
/// This method returns `()` if it succeeded, or `Err(msg)`
|
|
/// otherwise.
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `msg` - The message to send.
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```rust
|
|
/// # use bastion::prelude::*;
|
|
/// #
|
|
/// # #[cfg(feature = "tokio-runtime")]
|
|
/// # #[tokio::main]
|
|
/// # async fn main() {
|
|
/// # run();
|
|
/// # }
|
|
/// #
|
|
/// # #[cfg(not(feature = "tokio-runtime"))]
|
|
/// # fn main() {
|
|
/// # run();
|
|
/// # }
|
|
/// #
|
|
/// # fn run() {
|
|
/// # Bastion::init();
|
|
/// #
|
|
/// let msg = "A message containing data.";
|
|
/// Bastion::broadcast(msg).expect("Couldn't send the message.");
|
|
///
|
|
/// # Bastion::children(|children| {
|
|
/// # children.with_exec(|ctx: BastionContext| {
|
|
/// # async move {
|
|
/// // And then in every children groups's elements' future...
|
|
/// msg! { ctx.recv().await?,
|
|
/// ref msg: &'static str => {
|
|
/// assert_eq!(msg, &"A message containing data.");
|
|
/// };
|
|
/// // We are only broadcasting a `&'static str` in this
|
|
/// // example, so we know that this won't happen...
|
|
/// _: _ => ();
|
|
/// }
|
|
/// #
|
|
/// # Ok(())
|
|
/// # }
|
|
/// # })
|
|
/// # }).unwrap();
|
|
/// #
|
|
/// # Bastion::start();
|
|
/// # Bastion::stop();
|
|
/// # Bastion::block_until_stopped();
|
|
/// # }
|
|
/// ```
|
|
pub fn broadcast<M: Message>(msg: M) -> Result<(), M> {
|
|
debug!("Bastion: Broadcasting message: {:?}", msg);
|
|
let msg = BastionMessage::broadcast(msg);
|
|
let envelope = Envelope::from_dead_letters(msg);
|
|
trace!("Bastion: Sending envelope: {:?}", envelope);
|
|
// FIXME: panics?
|
|
SYSTEM
|
|
.sender()
|
|
.unbounded_send(envelope)
|
|
.map_err(|err| err.into_inner().into_msg().unwrap())
|
|
}
|
|
|
|
/// Sends a message to the system to tell it to start
|
|
/// handling messages and running children.
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```rust
|
|
/// use bastion::prelude::*;
|
|
///
|
|
/// # #[cfg(feature = "tokio-runtime")]
|
|
/// # #[tokio::main]
|
|
/// # async fn main() {
|
|
/// # run();
|
|
/// # }
|
|
/// #
|
|
/// # #[cfg(not(feature = "tokio-runtime"))]
|
|
/// # fn main() {
|
|
/// # run();
|
|
/// # }
|
|
/// #
|
|
/// # fn run() {
|
|
/// Bastion::init();
|
|
///
|
|
/// // Use bastion, spawn children and supervisors...
|
|
///
|
|
/// Bastion::start();
|
|
///
|
|
/// // The system will soon start, messages will
|
|
/// // now be handled...
|
|
/// #
|
|
/// # Bastion::stop();
|
|
/// # Bastion::block_until_stopped();
|
|
/// # }
|
|
/// ```
|
|
pub fn start() {
|
|
debug!("Bastion: Starting.");
|
|
let msg = BastionMessage::start();
|
|
let envelope = Envelope::from_dead_letters(msg);
|
|
trace!("Bastion: Sending envelope: {:?}", envelope);
|
|
// FIXME: Err(Error)
|
|
SYSTEM.sender().unbounded_send(envelope).ok();
|
|
}
|
|
|
|
/// Sends a message to the system to tell it to stop
|
|
/// every running children groups and supervisors.
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```rust
|
|
/// use bastion::prelude::*;
|
|
///
|
|
/// # #[cfg(feature = "tokio-runtime")]
|
|
/// # #[tokio::main]
|
|
/// # async fn main() {
|
|
/// # run();
|
|
/// # }
|
|
/// #
|
|
/// # #[cfg(not(feature = "tokio-runtime"))]
|
|
/// # fn main() {
|
|
/// # run();
|
|
/// # }
|
|
/// #
|
|
/// # fn run() {
|
|
///
|
|
/// Bastion::init();
|
|
///
|
|
/// // Use bastion, spawn children and supervisors...
|
|
///
|
|
/// Bastion::start();
|
|
///
|
|
/// // Send messages to children and/or do some
|
|
/// // work until you decide to stop the system...
|
|
///
|
|
/// Bastion::stop();
|
|
/// # Bastion::block_until_stopped();
|
|
/// # }
|
|
/// ```
|
|
pub fn stop() {
|
|
debug!("Bastion: Stopping.");
|
|
let msg = BastionMessage::stop();
|
|
let envelope = Envelope::from_dead_letters(msg);
|
|
trace!("Bastion: Sending envelope: {:?}", envelope);
|
|
// FIXME: Err(Error)
|
|
SYSTEM.sender().unbounded_send(envelope).ok();
|
|
}
|
|
|
|
/// Sends a message to the system to tell it to kill every
|
|
/// running children groups and supervisors
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```rust
|
|
/// use bastion::prelude::*;
|
|
///
|
|
/// # #[cfg(feature = "tokio-runtime")]
|
|
/// # #[tokio::main]
|
|
/// # async fn main() {
|
|
/// # run();
|
|
/// # }
|
|
/// #
|
|
/// # #[cfg(not(feature = "tokio-runtime"))]
|
|
/// # fn main() {
|
|
/// # run();
|
|
/// # }
|
|
/// #
|
|
/// # fn run() {
|
|
/// Bastion::init();
|
|
///
|
|
/// // Use bastion, spawn children and supervisors...
|
|
///
|
|
/// Bastion::start();
|
|
/// // Send messages to children and/or do some
|
|
/// // work until you decide to kill the system...
|
|
///
|
|
/// Bastion::kill();
|
|
/// # Bastion::block_until_stopped();
|
|
/// # }
|
|
/// ```
|
|
pub fn kill() {
|
|
debug!("Bastion: Killing.");
|
|
let msg = BastionMessage::kill();
|
|
let envelope = Envelope::from_dead_letters(msg);
|
|
trace!("Bastion: Sending envelope: {:?}", envelope);
|
|
// FIXME: Err(Error)
|
|
SYSTEM.sender().unbounded_send(envelope).ok();
|
|
|
|
let handle = SYSTEM.handle();
|
|
let system = crate::executor::run(async { handle.lock().await.take() });
|
|
if let Some(system) = system {
|
|
debug!("Bastion: Cancelling system handle.");
|
|
system.cancel();
|
|
}
|
|
|
|
SYSTEM.notify_stopped();
|
|
}
|
|
|
|
/// Blocks the current thread until the system is stopped
|
|
/// (either by calling [`Bastion::stop`] or
|
|
/// [`Bastion::kill`]).
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```rust
|
|
/// # #[cfg(feature = "tokio-runtime")]
|
|
/// # #[tokio::main]
|
|
/// # async fn main() {
|
|
/// # run();
|
|
/// # }
|
|
/// #
|
|
/// # #[cfg(not(feature = "tokio-runtime"))]
|
|
/// # fn main() {
|
|
/// # run();
|
|
/// # }
|
|
/// #
|
|
/// # fn run() {
|
|
/// use bastion::prelude::*;
|
|
///
|
|
/// Bastion::init();
|
|
///
|
|
/// // Use bastion, spawn children and supervisors...
|
|
///
|
|
/// Bastion::start();
|
|
/// // Send messages to children and/or do some
|
|
/// // work...
|
|
///
|
|
/// # Bastion::stop();
|
|
/// Bastion::block_until_stopped();
|
|
/// // The system is now stopped. A child might have
|
|
/// // stopped or killed it...
|
|
/// # }
|
|
/// ```
|
|
pub fn block_until_stopped() {
|
|
debug!("Bastion: Blocking until system is stopped.");
|
|
SYSTEM.wait_until_stopped();
|
|
}
|
|
}
|
|
|
|
impl Debug for Bastion {
|
|
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
|
fmt.debug_struct("Bastion").finish()
|
|
}
|
|
}
|