据我所知,DDD中有两种类型的事件。在同一过程中跨多个进程运行。
应如何处理事件订阅和调度?
我将提供一个下订单的示例。下订单时(第一范围内),您必须更新库存(第二BC)。
因此,在OrderAggregate中,您将具有一些创建订单的方法,最后它将在Domain.Events列表中添加一个事件(例如OrderPlacedEvent)。
现在,假设您在第1个受限上下文中发送确认电子邮件。谁应该通知SendEmailEventHandler实际发送电子邮件?
那么谁负责将事件分发给所有相关方,在本例中是SendEmailEventHandler?
此外,由于应该将事务扩展到第二个有界上下文,因此谁应该分发事件?我知道一条消息总线,但是如果没有的话?
我现在设计的方式是在Domain.Aggregate中,我有一个AddEvent(IDomainEvent event)方法,该方法可以由AggregateRoot类(域聚合的基类)使用。
聚合执行某项操作时,它将添加来自特定操作的事件列表。
StartOrder()=> OrderAggregate方法
OrderStartedEvent()=> DomainEvent
在Application.Layer中,我有一个UseCaseHandler(发挥作用的地方),在这里我调用聚合方法和存储库(即所有)。
在基础架构中,我有一个存储库,该存储库对ORM进行了抽象,并且仅提供用于添加,更新和删除的方法,以及一种将通过其ID获取聚合的方法。
根据我当前的设计,存储库是在提交之前调度事件的存储库。
这就是仓库的样子
protected override async Task AddAsync(TAggregate aggregate, CancellationToken token = default(CancellationToken))
{
using (ITransaction transaction = Session.BeginTransaction())
{
await Session.SaveAsync(aggregate, aggregate.Id, token);
/// => dispatch domain.Event to all interested parties
try
{
await transaction.CommitAsync();
}
catch
{
await transaction.RollbackAsync();
throw;
}
}
}
第一疑点:现在,这部分代表调度,我不确定。从我的角度来看,存储库是否应该负责分发,但我仍然不确定?
这是Application UseCaseHandler的外观
private IOrderRepository _orderRepository;
public async Task HandleAsync(CreateOrderRequest request, CancellationToken? cancellationToken = null)
{
OrderAggregate aggregate = await _orderRepository.GetByIdAsync(request.Id);
aggregate.CreateDraftOrder(); /// => adds the OrderPlacedEvent()
await _orderRepository.CreateOrderAsync(aggregate);
}
第二个未知数:更重要的地方和谁应该处理订阅?
答案 0 :(得分:1)
您想查看Udi Dahan的Reliable Messaging with Distributed Transactions。
摘要:如果您需要跨边界可靠地传递消息,那么您需要设计系统,以使出站消息随域模型的更改而持久地存储,您需要重试管道以将所有未发送的消息发送出去被确认后,您需要在邮件上使用清晰的身份语义,以便使用者可以识别重复项,并且您需要在收到第二份邮件副本时会做明智事情的使用者。
另请参见:Life Beyond Distributed Transactions,作者Pat Helland。