#actors #erlang-otp #toolkit #supervision

agner

受 Erlang/OTP 启发的 actor 工具包

30 个版本

0.4.1 2023 年 8 月 12 日
0.3.17 2023 年 8 月 12 日
0.3.16 2023 年 7 月 28 日
0.3.12 2023 年 1 月 22 日
0.3.11 2022 年 10 月 7 日

#1 in #erlang-otp

Download history 38/week @ 2024-07-03 23/week @ 2024-07-24

61 每月下载量

MIT 许可证

130KB
3K SLoC

agner — 进程 actors。

注意:目前这是一个研究项目,即 API 在 0.3.x 版本内可能发生不兼容的更改。

如前所述,agner 受 Erlang/OTP 启发,因此与实际框架的任何相似之处,无论是支持的还是已弃用的,都是纯粹故意的。 :)

actors

actor 是一个具有以下属性的活动

  • 并行运行(实现为 Future);
  • 有一个句柄(ActorID);
  • 可以接收消息;
  • 当终止时 — 产生退出原因(Exit);
  • 任何两个 actors 都可以互相 链接
    • 如果其中一个链接的 actors 以除了 Exit 的其他原因退出 — 另一个接收退出信号;
    • 如果接收退出信号的进程没有 "捕获退出信号",它也将被终止。

实现 Actor

actor 的行为由以下内容定义

  • 其参数的类型;
  • 它接受的消息的类型;
  • 行为函数。

为了实现一个 actor,应该定义一个异步函数,该函数

示例

use agner::actors::{Context, Exit, Never};

async fn shutdown_after_six_messages(context: &mut Context<String>, actor_name: String) {
    for i in 0..6 {
        let message = context.next_message().await;
        eprintln!("Actor {:?} received {:?}", actor_name, message);
    }
}

启动 Actor

actors 不能独立运行,它们需要一个 actor 系统 来启动。这是必要的,以避免仅仅使用库就强加全局状态。一个 System 是 actors 运行的范围。

示例

use agner::actors::{System, Context, Exit, Never};

async fn a_dummy(context: &mut Context<Option<String>>, actor_name: String) {
    eprintln!("{}: hi!", actor_name);

    while let Some(message) = context.next_message().await {
        eprintln!("{}: received {:?}", actor_name, message);
    }

    eprintln!("{}: bye!", actor_name);
}

#[tokio::main]
async fn main() {
    // create a system with default configuration
    let system = System::new(Default::default());

    let actor_id = system.spawn(
        a_dummy,
        "the-dummy".to_owned(),
        Default::default())
            .await.expect("Failed to spawn an actor");

    system.send(actor_id, Some("one".to_owned())).await;
    system.send(actor_id, Some("two".to_owned())).await;
    system.send(actor_id, Some("three".to_owned())).await;
    system.send(actor_id, Option::<String>::None).await;

    let exit_reason = system.wait(actor_id).await;
    eprintln!("{} exited: {:?}", actor_id, exit_reason);
}

终止 Actor

“故意”终止

从行为函数返回

如果行为函数返回,则行为者终止。行为函数的返回类型必须实现Into<Exit>特质。

示例

use std::convert::Infallible;
use agner::actors::{Context, Exit};

async fn unit_is_normal_exit(_context: &mut Context<Infallible>, _args:()) {}

async fn result_into_exit(_context: &mut Context<Infallible>, _args:()) -> Result<(), Exit> {
    Ok(()) // Equivalent to `Err(Exit::normal())`
}

调用 Context::exit

示例

use std::convert::Infallible;
use agner::actors::{Context, Exit};

async fn normal_exit(context: &mut Context<Infallible>, args: ()) -> Infallible {
    context.exit(Exit::normal()).await;
    unreachable!()
}

外部终止

行为者可以通过调用System::exit(&self, ActorID, Exit)来终止。

在这种情况下,行为者会收到一个退出信号。如果行为者"捕获退出",它可以执行一个优雅的关闭(甚至继续运行)。也就是说,如果退出原因不是Exit::kill():在这种情况下,行为者将直接终止,其链接的行为者随后也会收到退出信号。

监督

由于整个项目都是基于Erlang/OTP,因此与OTP设计原则有一些(相当多的)相似之处,即

设计原则

启动和停止

TBD

统一监督器

TBD

混合监督器

TBD

内省

TBD

测试

TBD

依赖

~3–5.5MB
~93K SLoC