2013-04-27 66 views
0

我是CQRS和最终一致性模型的新手,所以如果这是一个愚蠢的问题,请原谅我。CQRS最终一致性事件依赖关系

鉴于我刚刚开始,我有一个在内存中的本地CommandBus和EventPublisher。我的事件被保存到RavenDB数据库以用于重放目的,但是事件被发布并且处理程序在本地被调用(不通过NServiceBus等进行外部排队)。 EventPublisher确实异步发布事件(a Task.Factory.StartNew)。

有时我的事件有依赖关系(例如,OrderShipmentStatusUpdated事件可以正确处理到ReadModel之前,必须将OrderReceived事件处理到ReadModel中)。

我该如何处理这种情况?使用Sagas?在如上所述的简单内存模型中,如何使用Sagas? “推迟”一个事件是否被认为是可以接受的(也许将其标记为延期,并简单地尝试重新处理所有延期事件“偶尔”)?

有什么策略可以解决这个问题?

谢谢。

+0

您以异步方式发布事件的原因?如果这些事件是同步发布的,那么您将不会遇到事件的顺序问题,并且您不应该遇到最终一致性问题,因为它们将与命令在同一个线程中运行。 – Sarmaad 2013-04-27 14:42:06

+0

表现。除非我在所有的Web请求中同步并且只有1个服务器,否则我仍然会遇到问题,不是吗? – Jeff 2013-04-27 17:16:32

+0

@Jeff:我认为Sarmaad意味着OrderReceived和OrderShipmentStatusUpdated应该被同步处理。 – IlliakaillI 2013-04-28 04:16:41

回答

3

大部分时间重试的队列解决了这些问题。如果你的handler/aggregate/denormalizer不能处理消息,因为不满足前提条件 - 很难做到。然后你会从队列中处理更多的消息,直到这个消息再次可见。如果消息失败超过3次 - 丢弃它为错误队列进一步分析。

如果这是一个预期的工作流程,并且您实际上必须等待 - 如果不使用DDD /事件源进行建模,则创建Saga。如果使用DDD/Event Sourcing - Aggregates进行建模,则大多数情况下都会覆盖此类功能。

1

这是更好地从读模式从事件存储,而不是数据使用的数据处理OrderShipmentStatusUpdated事件,这将解决与最终一致性连接的问题。

活动商店是唯一真相的来源。

+0

如何确保事件在仅使用内存甚至tpublisher时同步处理? – Jeff 2013-04-28 04:30:39

+0

你是说我的读取模型事件处理程序(denormalizers)应该使用我的EventSource作为更新读取模型的手段? – Jeff 2013-04-28 19:33:18

2

问题是为什么事件不按顺序到达?

如果是因为“技术力量”,你可以看看你的基础架构解决这一点,但通常这需要一个完全成熟的消息队列。

如果邮件/事件了,因为“业务流程”的同步的,那么你可以看看英雄传奇/ ProcessManager的。看看Greg Young使用event store as queue的方法。

为了得到你的问题有关推迟事件:你可以考虑是利用骨料所需的排序模型采用一种简化的方法。它只会在满足条件时才会消耗事件并通知读取方。该视图将只投影已经被聚合“验证”的事件。您可以在模型中明确隐式概念。不利的一面是你会有更多的事件产生。 (是的,没有什么是免费的)

看一看Rinat Abdullin’s approach这一点。这是一个古老而有趣的帖子,也许可以参考Being The Worst播客,它也涵盖了其中的一些内容。

2

我同意ILICH。

发生的事件和阅读模型应该报告。阅读模型不应该有能力验证事件。

在域模型中运输逻辑可能比较容易,而不是创建一个新的传奇。

另一种方式在一个较小的项目,“欺骗”是用事件作为触发从eventstore阅读。所以当你的阅读模型得到一个事件通知时,它应该加载来自事件库的所有“新”事件。这可确保在运输过程中不会丢失任何东西,并简化您使用公交车的方式。

在原型阶段,它也可以让你随意吹掉你的阅读模型,并让它们自动重建。

我保留了一个“作业历史”的小表,它反映了处理特定读取模型所消耗的最新事件。如果我想更改读取模型的模式,我只需删除相应的记录。

1

在同步/异步事件发布的问题:

所谓具有EventCommit对象包裹给定DomainEvents有一个自己的提交ID持续到事件存储,我们可以异步处理的EventCommit对象,而DomainEvents内同步发布了EventCommit。包装发生在我们的UnitOfWork中,当请求对给定聚合的更改时,跟踪我们的内存中聚合。

在读取端,commit-id可用于在将事件分派给处理程序之前直接验证dequeing过程中的正确排序。