2 个不稳定版本
0.2.0 | 2023年10月16日 |
---|---|
0.1.0 | 2023年5月13日 |
#14 在 #concurrently
98KB
2K SLoC
通用状态机管理器
设计特性
- 使状态机成为可重用的模块化单元
- 使用其他状态机的状态机知道它们可以使用什么,但正在使用的状态机不知道使用它们的状态机
- 无任务/线程
- 同时处理多个状态机
- 触发其他状态机,等待它们完成,然后继续
- 创建/删除计时器
- 向状态机组外发送通知
- 向自身发送事件
- 从状态机组外接受事件
- 鼓励将状态机实现以
(<State>, <Event>)
格式表示
灵感来源
概述
StateMachine
首先注册到 StateMachineManager
,我将简单地称之为 Manager
。每次对 Manager::cycle()
的调用都处理单个事件。单个事件对应于单个状态机的运行。 Manager
访问 Controller
的内容并对其进行操作。单个 Controller
在 Manager
注册的所有状态机之间共享。
有两种类型的事件 UserEvent
和 SystemEvent
。 UserEvent
传递给 StateMachine::cycle()
,而 SystemEvent
则不传递。 StateMachine::cycle()
接受一个 &mut Controller
和一个 UserEvent
。 StateMachine
使用 Controller
中的函数来向事件队列添加/删除事件;除了与计时器相关的函数之外,所有函数都这样做。 SystemEvent
被管理器消耗并用于修改 Controller
的内部或向状态机组外发送数据或通知。
基于节点的状态机管理器(开发中)
目标
- 将状态机输入处理与给定 状态的当前枚举 解耦
- 状态指示所有输入都进入同一个汇点(管理员的
signal_queue
);这允许电梯和过渡被统一处理,从而避免了通过Box<dyn Signal>
带来的类型不透明。
实际上,设计应该将最多三个消息流连接到特定的状态机。
I/O
- 一个
Input
(处理外部和内部事件)
Signal {
id: StateId<K>,
input: I,
}
两个输出
Signal
输出(事件意味着要作为其他状态机的输入进行处理)Notification
输出(事件意味着要由任何不是由给定signal_queue
提供输入的状态机处理)
新的StateMachineManager
拥有
- 状态存储层(使用
NodeStorage
) - 输入事件流
- 状态机处理器
StateMachineManager
负责
- 将
Signal
路由到适当的状态机 - 将
ProcessorContext
注入到状态机中:这一动作允许状态机并发循环
NodeStore
负责
- 插入和更新各种状态层次结构
- 操作通过在
Arc<Mutex<_>>
容器中保留所有节点树来并发执行。
这允许NodeStore
存储
- 通过增加
Arc
计数并插入每个子节点的新条目来创建指向同一树的多个索引(通过新的DashMap键插入)
- 允许每个状态树具有独立的内部可变性,解耦无关状态与资源竞争
基于节点的TimeoutManager
(开发中)
考虑
- 每个
StateId<K>
只有一个活动计时器,状态机不需要跟踪发送到通知的Operation::Set(Instant::now())
。因此,所有计时器都应可按StateId<K>
索引。 - 同一
StateId<K>
的新Operation::Set
应覆盖旧计时器。 - 超时应发出与相关状态机相关的
Signal
。
方法
TimeoutManager
实现了一个每tick轮询的方法来解析超时:https://github.com/knox-networks/core/blob/83d57647e38a55c5cfecacca8c89ebe98d45ab68/common/src/state_machine/timeout.rs#L170-L193TimeoutManager
接受两种类型的输入,设置和取消(超时):https://github.com/knox-networks/core/blob/83d57647e38a55c5cfecacca8c89ebe98d45ab68/common/src/state_machine/timeout.rs#L85-L89- 超时存储在
TimeoutLedger
中:https://github.com/knox-networks/core/blob/83d57647e38a55c5cfecacca8c89ebe98d45ab68/common/src/state_machine/timeout.rs#L25-L32 TimeoutLedger
包含一个BTreeMap
,它按Instant
索引 ID,以及一个HashMap
,它按 ID 索引Instant
。这种双重索引允许超时取消操作无需提供要移除的Instant
。
依赖项
~10–18MB
~208K SLoC