Насколько я понимаю, в DDD есть два типа событий. Бегал по одному и тому же процессу и по нескольким процессам.
Как следует обрабатывать подписку и отправку события?
Я приведу пример для размещения заказа. Когда вы размещаете заказ (1-й ограниченный контекст), вы должны обновить запас (2-й до н.э.).
Таким образом, в OrderAggregate у вас будет какой-то метод, который создает заказ, и в конце он добавит событие, например OrderPlacedEvent, в список Domain.Events.
Теперь при условии, что в первом ограниченном контексте вы отправите подтверждение по электронной почте. Кто должен уведомить SendEmailEventHandler о фактической отправке электронной почты?
Итак, кто несет ответственность за отправку события всем заинтересованным сторонам, в данном случае SendEmailEventHandler?
Более того, поскольку транзакция должна быть расширена до 2-го ограниченного контекста, кто должен отправлять событие? Я знаю шину сообщений, но если у вас ее нет?
Способ, которым я сейчас занимаюсь, заключается в том, что в моем Domain.Aggregate у меня есть метод AddEvent (событие IDomainEvent), который доступен классом AggregateRoot (базовый класс для агрегатов домена).
Когда агрегат что-то делает, он добавляет в этот список событие определенного действия.
StartOrder () => Метод OrderAggregate
OrderStartedEvent () => DomainEvent
В Application.Layer у меня есть UseCaseHandler (игровая площадка), где я вызываю агрегатные методы и репозитории (вот и все).
В инфраструктуре у меня есть репозиторий, который абстрагирует ORM и предоставляет только методы для добавления, обновления и удаления + метод, который будет получать агрегат по его идентификатору.
Из моего текущего проекта хранилище - это то, что отправляет события перед фиксацией.
Так вот как выглядит репо
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;
}
}
}
1-я Сомнение: Теперь эта часть представляет отправку, в которой я не совсем уверен. Должен ли репозиторий отвечать за диспетчеризацию, с моей точки зрения, это должно быть, но все же я не уверен?
А вот так выглядит приложение 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);
}
2-й Неизвестный: Где и кто должен обрабатывать подписку важнее?