2013-04-27 82 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過程中的正確排序。