8个版本
0.2.3 | 2019年1月17日 |
---|---|
0.2.2 | 2019年1月7日 |
0.1.9 | 2019年1月3日 |
0.1.8 | 2018年10月1日 |
0.1.0 | 2018年7月17日 |
#919 in 异步
16KB
275 行
Riker命令查询责任分离(CQRS)
概述
命令查询责任分离(CQRS)基于事件源,提供了一种更结构化的持久化方法。仅事件源本身适用于在具有固定数量的actor的actor系统中恢复单个actor状态。这可以进一步扩展,以便可以将数据实体建模为actor。例如,一个实体可以是用户、账户、帖子、交易、订单等,其中每个实例都由其自身的actor实例表示。
要更改实体,需要向表示该实体的actor发送命令。例如,要更改用户实体的密码,可以发送UpdatePasswordCmd
,或要禁用用户,可以发送DisableUserCmd
。当actor收到命令时,它会验证该命令,然后发出一个将被持久化和应用的事件
UpdatePasswordCmd => PasswordUpdatedEvt
DisableUserCmd => UserDisabledEvt
为了帮助设置实体和命令管理,Riker CQRS是一个独立的crate(riker-cqrs
),它引入了
- 实体管理
- 基于命令的消息传递
由于每个实体都有自己的actor,因此需要有一个协调器,在需要时创建actor并将命令路由到正确的actor。还需要进行基本的簿记,以便actor可以在一段时间的不活动后休眠并从内存中删除,然后在需要处理命令时恢复。
让我们看看如何设置一个表示银行账户的BankAccount
的实体管理器
Cargo.toml
:
[dependencies]
riker = "0.1.8"
riker-default = "0.1.8"
riker-cqrs = "0.1.8"
代码
use riker::actors::*;
use riker_default::DefaultModel;
use riker_cqrs::*;
let model: DefaultModel<TestMsg> = DefaultModel::new();
let sys = ActorSystem::new(&model).unwrap();
let em = Entity::new(&sys,
BankAccountProps,
"BankAccont",
None).unwrap();
在此,创建了一个Entity
,它将管理所有银行账户实例。如果需要,它将创建新的actor并路由命令。
让我们创建一个新的银行账户并进行首次存款
let number = "12345678";
let name = "Dolores Abernathy";
// create bank account
let cmd = CQMsg::Cmd(number.into(), Protocol::CreateAccountCmd(name.into()));
em.tell(cmd, None);
// deposit $1000
let cmd = CQMsg::Cmd(number.into(), Protocol::DepositCmd(1000));
em.tell(cmd, None);
命令需要一个ID,根据该ID,实体管理器将路由命令到该ID的actor。如果没有在内存中为该ID提供活动的actor,则管理器将启动一个actor。在处理命令之前,将加载与该ID相关的任何事件并恢复actor状态。
而不是直接使用actor_of
管理actor创建,实体管理器会这样做。您会注意到示例中的Entity::new
传递了BankAccountProps
。这是一个实现EntityActorProps
trait的结构体。
由于每个实体演员都需要自己的唯一ID,因此用于 actor_of
的标准 Props
是不够的。相反,实现了 EntityActorProps
struct BankAccountProps;
impl EntityActorProps for BankAccountProps {
type Msg = Protocol;
fn props(&self, id: String) -> BoxActorProd<Self::Msg> {
Props::new_args(Box::new(BankAccountActor::new), id)
}
}
依赖项
~8MB
~156K SLoC