我遇到了以下代码:
public class ShippingSaga : Saga<ShippingSagaData>,
ISagaStartedBy<OrderAccepted>,
ISagaStartedBy<CustomerBilledForOrder>
{
public void Handle(CustomerBilledForOrder message)
{
this.Data.CustomerHasBeenBilled = true;
this.Data.CustomerId = message.CustomerId;
this.Data.OrderId = message.OrderId;
this.CompleteIfPossible();
}
public void Handle(OrderAccepted message)
{
this.Data.ProductIdsInOrder = message.ProductIdsInOrder;
this.Data.CustomerId = message.CustomerId;
this.Data.OrderId = message.OrderId;
this.CompleteIfPossible();
}
private void CompleteIfPossible()
{
if (this.Data.ProductIdsInOrder != null && this.Data.CustomerHasBeenBilled)
{
this.Bus.Send<ShipOrderToCustomer>(
(m =>
{
m.CustomerId = this.Data.CustomerId;
m.OrderId = this.Data.OrderId;
m.ProductIdsInOrder = this.Data.ProductIdsInOrder;
}
));
this.MarkAsComplete();
}
}
}
从上面的代码看,传奇似乎是某种更高级别的协调员/事件控制者。这是真的吗?如果是这样,它们是否仅用于事件驱动架构?最后,是INFRASTRUCTURE的传奇部分?
第一个查询似乎得到了解答。但他们真正属于责任范围,即基础设施?领域? 。这些仅适用于EDA吗?
答案 0 :(得分:3)
警告:有一些混淆,尤其是关于“Saga”定义的nservicebus左右;见下文。
从根本上说,流程管理器是读取模型 - 您可以从事件历史记录中重新编写它们,并查询它们以查找应该运行的命令列表。
它们类似于人类正在查看视图,并向写入模型发送命令。有关此观点的更多信息,请参阅Rinat Abdullin的论文Evolving Business Processes。
它们用作业务流程的描述,也就是说它们标识应由聚合运行的其他决策(命令)。在实现中,它们是非常多的状态机 - 给定事件X和事件Y,进程管理器处于状态(XY),并且它将推荐的命令是固定的。
如果你将状态机(纯逻辑)与副作用(与总线的交互)分开,我发现它们更容易思考。
public class ShippingSaga : Saga,
ISagaStartedBy<OrderAccepted>,
ISagaStartedBy<CustomerBilledForOrder>
{
public void Handle(CustomerBilledForOrder message)
{
this.process.apply(message);
this.CompleteIfPossible();
}
public void Handle(OrderAccepted message)
{
this.process.apply(message);
this.CompleteIfPossible();
}
private void CompleteIfPossible()
{
this.process.pendingCommands().each ( m=>
this.Bus.Send(m);
}
}
}
或等效 - 如果您更愿意考虑不可变数据结构
public class ShippingSaga : Saga,
ISagaStartedBy<OrderAccepted>,
ISagaStartedBy<CustomerBilledForOrder>
{
public void Handle(CustomerBilledForOrder message)
{
this.process = this.process.apply(message);
this.CompleteIfPossible();
}
public void Handle(OrderAccepted message)
{
this.process = this.process.apply(message);
this.CompleteIfPossible();
}
private void CompleteIfPossible()
{
this.process.pendingCommands().each ( m=>
this.Bus.Send(m);
}
}
}
因此,运输进程是根据业务域定义的,NServiceBus“Saga”将业务域的一部分与总线基础结构相连接。关注点不是很精彩。
我在引号中使用“Saga”是因为 - NService bus sagas并不适合prior use of the term
术语saga通常用于讨论CQRS,以指代在有界上下文和聚合之间协调和路由消息的一段代码。但是,出于本指南的目的,我们更喜欢使用术语流程管理器来引用此类代码工件。这有两个原因:
- 有一个众所周知的,预先存在的saga一词的定义,其含义与通常与CQRS有关的含义不同。
- 术语流程管理器是对此类代码工件执行的角色的更好描述。