事件溯源:触发其他事件和事件重建状态
我正在努力弄清楚通过重播 EventStore 中的事件来重建模型时应该发生什么,特别是当事件可能触发其他事件发生时。
例如,已购买 10 次的用户应晋升为首选客户,并收到一封向他们提供某些促销活动的电子邮件。
我们显然不希望每次为该用户重建模型时都发送电子邮件,但是当我们重播第 10 个 PurchaseMadeEvent
时,如何阻止这种情况发生?
I'm struggling to get my head around what should happen when rebuilding the model by replaying events from the EventStore, in particular when events may trigger other events to happen.
For example, a user who has made 10 purchases should be promoted to a preferred customer and receive an email offering them certain promotions.
We clearly don't want the email to be sent every time we rebuild the model for that user, but how do we stop this from happening when we replay our 10th PurchaseMadeEvent
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
事件链可能非常棘手并且很容易失控,所以我会尽可能避免它。例如,在您描述的场景中,我会引发
UserPromotedEvent
(甚至可能使用PromoteUserCommand
),但是我不会考虑实际/物理发送电子邮件作为我的域的一部分。相反,我会为UserPromotedEvent
创建额外的处理程序/反规范化器,这将注册发送电子邮件的需要,并很可能进行一些额外的检查。之后,另一个进程将收集尚未处理的电子邮件的信息并发送它们。这种方法可以缓解由于无法完全访问/可扩展的电子邮件网关而可能出现的问题。更一般而言 - 事件链的需要经常表明您应该考虑实现 Saga 用于该过程。
Events chaining can be very tricky and easily run out of control, so I'd avoid it as much as possible. For example in the scenario you're describing I'd raise a
UserPromotedEvent
(maybe even using thePromoteUserCommand
), however I wouldn't consider actual/physical sending of an email as part of my domain. Instead I would create additional handler/denormalizer forUserPromotedEvent
that would register the need of sending the email with some additional checks quite possibly. After that another process would gather information of not yet processed emails and send them. This approach would mitigate the problems that might occur with not fully accessible/scalable email gateway.In more general - the need of events chaining very often indicates that you should consider implementing a Saga for the process.
您不应该从事件处理程序中引发事件 - 只是不要这样做!您应该使用 sagas 代替。
在您的情况下,saga 订阅
PurchaseMadeEvent
并发出PromoteCustomer
COMMAND,这会导致发生CustomerPromoted
事件。同样,还有另一个订阅CustomerPromoted
事件并发送SendEmailToPromotedCustomer
命令的传奇。当您重播事件时 - 只是不要订阅CustomerPromoted
事件的传奇。这就是命令和事件之间的区别。理解它很重要。事件告诉我们已经发生了什么,命令告诉我们将会发生什么。
You should not raise event from event handler - just don't do it! You should use sagas instead.
In your case, saga subscribes for
PurchaseMadeEvent
and issuesPromoteCustomer
COMMAND, which causes to happenCustomerPromoted
event. Again, there is another saga that subscribes forCustomerPromoted
event and sendsSendEmailToPromotedCustomer
command. When you are replaying events - just don't subscribe saga forCustomerPromoted
event.This is all about the difference between command and event. It is important to understand it. Events tell what already has happened, commands tell what will happen.
当您重播事件时,您并没有重播与生成这些事件相关的所有域逻辑。通常在您的域方法中您会引发一个事件;然后,该事件的引发应该更新该域对象的整体状态。
例如:
在此示例中,当重播我的事件时,将执行 OnPurchaseMade 事件处理程序,而不是域对象构造函数。与 PurchaseUpdatedEvent 相同 - 将执行它的事件处理程序,而不是引发该事件的域方法。
该事件包含更新域模型(并将更新应用到读取模型)所需的所有内容。执行的域方法使您能够引发事件。
我希望这有帮助。如果我需要提供更多信息,请告诉我。
祝你好运!!
When you replay events, you're not replaying all of the domain logic that went along with generating those events. Usually in your domain method you'll raise an event; the raising of that event then should update the overall state of that domain object.
For example:
In this example, when my events are replayed, the
OnPurchaseMade
event handler will get executed, not the domain object constructor. Same with thePurchaseUpdatedEvent
- it's event handler will get executed, not the domain method that raised the event.The event contains everything that you need to update the domain model (and apply the updates to the read model). The domain methods that get executed get you to the point that an event can be raised.
I hope this helps. Let me know if I need to provide more information.
Good luck!!