What is Bastion?

Bastion is a highly-available, fault-tolerant runtime system with dynamic dispatch oriented lightweight process model. It supplies actor model like concurrency with lightweight process implementation and utilize all the system resources efficiently with giving promise of at-most-once message delivery guarantee.

  • Message-based communication makes this project a lean mesh of actor system.
  • Runtime fault-tolerance makes it a good candidate for distributed systems.
  • Completely asynchronous runtime with NUMA-aware and cache-affine SMP executor.
  • Supervision system makes it easy to manage lifecycles.

Features

Bastion has awesome features.

Message-based communication

It makes this project a lean mesh of actor system. Without web servers, weird shenanigans, forced trait implementations, and static dispatch.

Runtime fault-tolerance

It makes it a good candidate for small scale distributed system code. If you want the smell of Erlang and the powerful aspects of Rust. That's it!

Supervision

It makes easy to manage lifecycles. Kill your application in certain condition or restart you subprocesses whenever a certain condition met. All up to you. And it should be up to you.

Examples

In a short way, you can use fort the proc-macro for Bastion:

use bastion::prelude::*;

#[fort::root]
async fn main(_: BastionContext) -> Result<(), ()> {
    println!("Running in Bastion runtime!");
    Ok(())
}

Or, you can configure every piece by yourself:

use bastion::prelude::*;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;

fn main() {
    Bastion::init();

    let started = AtomicBool::new(false);
    let started = Arc::new(started);

    Bastion::children(|children| {
        children.with_exec(move |ctx: BastionContext| {
            let started = started.clone();
            async move {
                println!("Started!");

                if started.swap(true, Ordering::SeqCst) {
                    println!("Already started once. Stopping...");

                    // This will ask the system to stop itself...
                    Bastion::stop();
                    // ...and this will stop this child immediately...
                    return Ok(());
                    // Note that if Err(()) was returned, the child would have been
                    // restarted (and if the system wasn't stopping).
                }

                // This will return None.
                let try_recv = ctx.try_recv().await;
                println!("try_recv.is_some() == {}", try_recv.is_some()); // false

                let answer = ctx
                    .current()
                    .ask_anonymously("Hello World!")
                    .expect("Couldn't send the message.");

                msg! { ctx.recv().await?,
                    msg: &'static str =!> {
                        println!(r#"msg == "Hello World!" => {}"#, msg == "Hello World!"); // true
                        let _ = answer!(ctx, "Goodbye!");
                    };
                    // This won't happen because this example
                    // only "asks" a &'static str...
                    _: _ => ();
                }

                msg! { answer.await?,
                    msg: &'static str => {
                        println!(r#"msg == "Goodbye!" => {}"#, msg == "Goodbye!"); // true
                    };
                    // This won't happen because this example
                    // only answers a &'static str...
                    _: _ => ();
                }

                // Panicking will restart the children group.
                panic!("Oh no!");
            }
        })
    })
    .expect("Couldn't start a new children group.");

    Bastion::start();
    Bastion::block_until_stopped();
}

Learn more about Bastion

Read the documentation, take a look at the examples, get involved in the project