【发布时间】:2018-11-06 13:30:48
【问题描述】:
据我了解,DDD 中有两种类型的事件。在同一进程下运行并跨多个进程运行。
应该如何处理事件的订阅和分发?
我将提供一个下订单的示例。当您下订单时(第一个有界上下文),您必须更新股票(公元前 2 年)。
因此,在 OrderAggregate 中,您将有一些创建订单的方法,最后它会将事件(例如 OrderPlacedEvent)添加到 Domain.Events 列表中。
现在假设在第一个有界上下文中,您将发送一封确认电子邮件。谁应该通知 SendEmailEventHandler 实际发送电子邮件?
那么谁负责将事件分发给所有相关方,在本例中为 SendEmailEventHandler ?
此外,由于事务应该扩展到第二个有界上下文,谁应该调度事件?我知道一个消息总线,但如果你没有呢?
我现在的设计方式是在我的 Domain.Aggregate 中有一个 AddEvent(IDomainEvent event) 方法,该方法由 AggregateRoot 类(域聚合的基类)提供。
当聚合做某事时,它会将来自特定操作的事件添加到该列表中。
StartOrder() => OrderAggregate 方法
OrderStartedEvent() => 领域事件
在 Application.Layer 中,我有一个 UseCaseHandler(操场),我在其中调用聚合方法和存储库(仅此而已)。
在基础设施中,我有一个存储库,它抽象了 ORM 并只提供了添加、更新和删除的方法 + 一个通过它的 id 获取聚合的方法。
根据我当前的设计,存储库是在提交之前分派事件的存储库。
这就是 repo 的样子
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);
}
第二个未知数:在哪里和谁应该更重要地处理订阅?
【问题讨论】:
标签: architecture event-handling domain-driven-design messaging software-design