#tree #erlang-otp #worker #process #supervision #async #tree-root

supertrees

基于 Tokio 的服务监督树,灵感来自 Erlang/OTP

3 个版本

0.1.2 2024 年 4 月 9 日
0.1.1 2024 年 4 月 9 日
0.1.0 2024 年 4 月 9 日

#605数据结构

LGPL-3.0-only

2MB
525

Docs Crates.io Build & test

supertrees – Rust 监督树

Trees with little gremlins and the moon

一个实验性的 Rust 包,以 Erlang/OTP 为灵感实现监督树。

有关详细信息,请参阅文档


lib.rs:

基于异步 Rust 的监督树,灵感来自 Erlang/OTP

此包为异步 Rust 提供了基于 Erlang/OTP 的监督树实现。它提供了一个可用于创建监督树的 Supertree 结构体,以及一个可以被添加到监督树中的工作器实现的 Worker 特性。

此包旨在与异步 Rust 和 Tokio 运行时一起使用,但理论上也可以与其他异步运行时一起使用。

在当前状态下,此包被视为实验性的,不应用于生产服务,除非您非常热衷于这个想法,并愿意为此包的开发做出贡献。值得注意的是,此包缺乏许多 Erlang/OTP 中的功能,例如监视、跟踪和分布式消息传递,尽管 Tokio 提供了可以与此包一起使用的跟踪和指标系统(尚未经过测试)。

有关详细示例,请参阅tests 目录中的集成测试。

功能

  • 监督树:使用根监督器创建监督树
  • 工作器:将工作器添加到监督树
  • 异步工作器:工作器是异步的,可以使用 async/await 语法
  • 进程隔离:通过进程分叉构建树,提供额外的隔离(目前未实现 IPC
  • 分层结构:创建工作器和监督器的层次结构
  • 重启策略:为工作器定义重启策略
  • 退避策略:为工作器定义退避策略

与 Erlang/OTP 的比较

  • 与 Erlang/OTP 不同,此包不提供分布式消息传递。另一个可供参考的包是 genserver,但它不提供 IPC。
  • 此包不提供监视或跟踪,但 Tokio 本身包含一个跟踪和指标系统,可以与此包一起使用。
  • Erlang/OTP 使用抢占式绿色线程调度器,而此crate使用Tokio运行时,这是一个协作式多任务运行时。
  • 树中的每个单独的监督者都是一个单独的线程,它们之间没有共享内存或IPC(尚未实现,欢迎提交PR)。这与Erlang/OTP使用的无共享架构形成对比。
  • Erlang/OTP经过实战检验,已在生产中使用数十年,而此crate尚未。

示例

使用此crate创建一个包含根监督者、两个子监督者和三个工作者的监督树的基本示例

use supertrees::{Restartable, Supertree, Worker};

#[derive(Debug)]
struct MyWorker {
    num: i32,
}

impl MyWorker {
    fn new(num: i32) -> Self {
        Self { num }
    }
}

impl Worker for MyWorker {
    // init() is called before the worker is started, and will be called
    // after each subsequent restart, so it should be safe to call this
    // repeatedly and  any state that needs to be reset should be reset here.
    fn init(
        &self,
    ) -> std::pin::Pin<Box<dyn std::future::Future<Output = ()> + Send + 'static>> {
        let num = self.num;
        Box::pin(async move {
            println!("hi, I'm worker num={num} :)");
        })
    }
}

// We must provide a restart and backoff policy for the worker, but we can
// use the default policies.
impl Restartable for MyWorker {}

let root = Supertree::new()
    .add_worker(MyWorker::new(1))
    .add_supervisor(|s| {
        s.add_worker(MyWorker::new(2))
            .add_supervisor(|s| s.add_worker(MyWorker::new(3)))
    });
dbg!(&root);

// Now you can start the supervision tree, which will run forever.
// Uncomment the line below to run the supervision tree.
// root.start();

依赖项