我有一个事件源系统,现在正在实现一个端点,该端点将从事件存储事件中重建读取侧数据存储。但是,我现在在处理事件方面遇到了似乎并发的问题。
我决定在重建过程中使用事件处理程序代码来处理事件。在系统的正常状态下(不是读取侧db重建),我的事件处理程序侦听它们订阅的事件并相应地更新投影。但是,当通过它们的事件处理程序在线处理这些事件时,我看到读取侧数据库的最终状态不一致的结果(即使它到达那里,有时也不会)。 我想这意味着他们的执行顺序混乱。
我不应该以这种方式使用事件处理程序吗?我认为由于我正在处理事件,因此以这种方式重用事件处理程序将是非常合适的。
我正在使用 MediatR 进行服务消息传递。所有事件处理程序都实现INotificationHandler
。
以下是代码示例:
IEnumerable<IEvent> events = await _eventRepo.GetAllAggregateEvents(aggId);
int eventNumber = 0;
foreach (var e in events)
{
if (e.Version != eventNumber + 1)
throw new EventsOutOfOrderException("Events were out of order while rebuilding DB");
var ev = e as Event;
// publish different historic events to event handlers which work with read DBs
switch (e.Type)
{
case EventType.WarehouseCreated:
WarehouseCreated w = new WarehouseCreated(ev);
await _mediator.Publish(w);
break;
case EventType.BoxCreated:
BoxCreated b = new BoxCreated(ev);
await _mediator.Publish(b);
break;
case EventType.BoxLocationChanged:
BoxLocationChanged l = new BoxLocationChanged(ev);
await _mediator.Publish(l);
break;
}
eventNumber++;
}
我已经尝试将await
关键字替换为对Wait()
的调用。
类似_mediator.Publish(bcc).Wait()
。
但这似乎不是一个好主意,因为它背后有异步代码。也不起作用。
我还尝试了排队事件的版本,让事件类型的案例在发布事件之前一直等到其版本位于队列的顶部。
类似的东西:
case EventType.BoxContentsChanged:
BoxContentsChanged bcc = new BoxContentsChanged(ev);
while (eventQueue.Peek() != bcc.Version)
continue;
await _mediator.Publish(bcc);
eventQueue.Dequeue();
break;
这也不起作用。
无论如何-如果有人对如何解决此问题有任何想法,我将非常感激。我不希望以同步的方式复制所有异步事件处理程序代码。
答案 0 :(得分:0)
我想最好的方法是同步,以确保一致性。这要求我在Replay服务中复制一些事件处理程序逻辑,并创建同步存储库方法。现在没有比赛条件,这很好。