#subsystem #pattern #orchestra #proc-macro #actor #graph #generate

orchestra-proc-macro

从单个注释过的结构体定义生成演员模式连接图 - 过程宏

17 个版本

0.4.0 2024 年 6 月 12 日
0.3.6 2024 年 5 月 8 日
0.3.5 2024 年 1 月 29 日
0.3.3 2023 年 7 月 28 日
0.0.1 2022 年 5 月 24 日

#54 in #subsystem

Download history 28604/week @ 2024-04-16 27882/week @ 2024-04-23 22299/week @ 2024-04-30 19812/week @ 2024-05-07 25100/week @ 2024-05-14 29588/week @ 2024-05-21 32299/week @ 2024-05-28 24533/week @ 2024-06-04 23250/week @ 2024-06-11 22734/week @ 2024-06-18 27635/week @ 2024-06-25 26167/week @ 2024-07-02 23121/week @ 2024-07-09 32043/week @ 2024-07-16 33817/week @ 2024-07-23 25535/week @ 2024-07-30

120,626 每月下载量
57 个 crate 中使用 (通过 orchestra)

MIT/Apache

175KB
4K SLoC

orchestra

orchestra 模式是一种部分演员模式,具有一个全局协调器来处理相关的工作项。

过程宏

该过程宏提供了一个方便的生成器,使用构建器模式,其核心是创建并启动一组子系统,这些子系统完全是声明性的。

    #[orchestra(signal=SigSigSig, event=Event, gen=AllMessages, error=OrchestraError)]
    pub struct Opera {
        #[subsystem(MsgA, sends: [MsgB])]
        sub_a: AwesomeSubSysA,

        #[cfg(any(feature = "feature1", feature = "feature2"))]
        #[subsystem(MsgB, sends: [MsgA])]
        sub_b: AwesomeSubSysB,
    }
  • 每个子系统都带有注释 #[subsystem(_)] 其中 MsgA 分别 MsgB 是该特定子系统消耗的消息。这些子系统中的每一个都必须实现具有正确特质的子系统特质。通常,这是通过使用 #[subsystem]#[contextbounds] 宏来实现的。
    • #[contextbounds(Foo, error=Yikes, prefix=wherethetraitsat)] 可以应用于 implfn 块。它将为泛型 Context 添加额外的特质约束,包括 Context: FooContextTrait,以及一些其他的约束。注意,这里的 Foo 指的是在 #[orchestra(..)] 宏中声明的子系统名称。
    • #[subsystem(Foo, error=Yikes, prefix=wherethetraitsat)] 是对上述内容的扩展,实现了 trait Subsystem<Context, Yikes>
  • error= 告诉乐团使用用户提供的错误类型,如果没有提供,则使用内置的错误类型。请注意,这是在整个调用中使用的错误类型,所以请确保为所有与您的应用程序相关的其他错误类型 E 实现 From<E>
  • event= 声明了一个外部事件类型,该类型将某些事件注入到乐团中,而不参与子系统模式。
  • signal= 定义了一个用于乐团的信号类型。这是所有子系统共享的“滴答”或“时钟”。
  • gen= 定义了一个包装 enum 类型,用于包装所有可以被 任何 子系统消费的消息。
  • 可以通过 #[cfg(feature = "feature")] 属性宏表达式来对功能进行功能门控。目前支持 anyallnotfeature
    /// Execution context, always required.
    pub struct DummyCtx;

    /// Task spawner, always required
    /// and must implement `trait orchestra::Spawner`.
    pub struct DummySpawner;

    fn main() {
        let _orchestra = Opera::builder()
            .sub_a(AwesomeSubSysA::default())
            .sub_b(AwesomeSubSysB::default())
            .spawner(DummySpawner)
            .build();
    }

在下面的 main 中,通过生成的、编译时错误生成器模式创建了乐团。

构建器要求在调用 build 方法之前,必须通过相应的设置方法设置所有子系统、行李字段(附加结构数据)和生成器。未能进行此类初始化将导致编译错误。这是通过将每个构建器字段编码为所谓的 state generics 来实现的,这意味着每个字段可以是 Init<T>Missing<T>,因此每个设置器都将特定结构字段的从 Missing 状态转换为 Init 状态。因此,如果您在期望 Init 的位置看到了关于 Missing 的编译时错误,通常意味着在调用 build 之前没有设置某些子系统或行李字段。

要排除子系统此类检查,可以给一些尚未准备好的、不打算包含在 orchestra 中的子系统设置 wip 属性。

    #[orchestra(signal=SigSigSig, event=Event, gen=AllMessages, error=OrchestraError)]
    pub struct Opera {
        #[subsystem(MsgA, sends: MsgB)]
        sub_a: AwesomeSubSysA,

        #[subsystem(MsgB, sends: MsgA), wip]
        sub_b: AwesomeSubSysB, // This subsystem will not be required nor allowed to be set
    }

行李字段可以初始化多次,但对于子系统则不然:子系统必须初始化一次(另一个编译时检查),或者可以被特殊的设置器方法(如 replace_<subsystem>)所替代。

任务生成器和子系统上下文必须使用 Spawner 和分别 SubsystemContext 实现。

调试

像往常一样,调试带有有缺陷的 proc-macros 时特别令人烦恼,请参阅 功能 "expand"

功能

功能 "expand"

expander 被用来生成更好的错误信息。使用 --features=orchestra/expand 启用。

功能 "dotgraph"

生成一个有向图,该图显示了根据声明的消息发送和消费的连接性。使用 --features=orchestra/dotgraph 启用。生成的文件路径将显示,其格式为 ${OUT_DIR}/${orchestra|lowercase}-subsystem-messaging.dot。使用 dot -Tpng ${OUT_DIR}/${orchestra|lowercase}-subsystem-messaging.dot > connectivity.dot 转换为例如 png 图像,或者使用您喜欢的 dot 文件查看器。它还创建一个与 .dot 图形一起的 .svg,可以直接使用。

注意事项

没有工具是没有警告的,orchestra也不例外。

大消息类型

与其他通道实现一样,不建议通过通道发送大消息。如果您需要传输超过几百字节的数据,请使用Box<_>将其包装起来,或者根据具体情况使用全局标识符来访问持久状态,例如数据库。

响应通道

将响应通道作为消息的一部分似乎非常有吸引力,并且在许多情况下,这些都是维护结构化数据流的非常方便的方式,但如果不谨慎使用,它们可能会给你带来麻烦。所需的小心谨慎涉及到以下三个方面:

  1. 循环消息依赖导致单线程子系统死锁
  2. 许多子系统过深的消息依赖
  3. 由于响应通道导致的延迟

每个问题都有多种解决方案,例如,通过本地缓存来修复对相同信息的频繁查找,或者在某些情况下,通过将子系统分割成多个来避免循环依赖,或者合并与某个子系统拓扑上紧密相关的微小部分,但这强烈依赖于orchestra使用的具体环境。

要找到这些问题,dotgraph功能提供了一种可视化子系统之间所有交互的方式,以子系统级别进行循环检测(目前还不是消息级别)。在生成阶段,请注意警告。

许可

许可方式任选其一

任选其一。

依赖项

~5MB
~98K SLoC