2011-09-10 23 views
3

我深入了我的CQRS和事件採購的第一次嘗試,並且我有幾點像某些指導一樣。我想實施一個SO風格的信譽系統。這看起來非常適合這種架構。具有CQRS和事件採購的SO風格信譽系統

以SO爲例。說一個問題upvoted這會產生一個UpvoteCommand它增加了問題的總分和火災QuestionUpvotedEvent

看起來好像作者的用戶聚集應該訂閱QuestionUpvotedEvent這可能會提高信譽評分。但是,如何/何時執行此訂閱對我而言並不清楚?在Greg Youngs的例子中,事件/命令處理在global.asax中是有線的,但這似乎並不涉及基於聚合ID的任何路由。

看起來好像每個用戶聚合都會訂閱每個QuestionUpvotedEvent,這似乎不正確,因此要使這樣的方案有效,事件處理程序必須展示行爲以確定該用戶是否擁有剛上架的問題。 Greg Young暗示,這不應該出現在事件處理程序代碼中,這應該只涉及狀態變化。

我在這裏錯了什麼?

任何指導非常讚賞。

編輯

我想我們在這裏討論的問題是什麼&用戶聚合體之間的相互聚集的溝通。我可以看到的一個解決方案是QuestionUpvotedEventReputationEventHandler訂閱,該ReputationEventHandler然後可以獲取相應的用戶AR並且在該對象上調用相應的方法,例如YourQuestionWasUpvoted。這反過來會產生用戶特定的事件,從而保留將來的重放能力。這是朝着正確的方向嗎?

EDIT 2

又見關於谷歌組here討論。

回答

6

我的理解是聚合本身不應該是訂閱事件。領域模型只會引發事件。它是訂閱事件的查詢端或其他基礎結構組件(例如電子郵件組件)。

域服務設計用於涉及多個聚合的用例/命令。

我會做在這種情況下什麼:

  • VoteUpQuestionCommand被調用。
  • 處理程序VoteUpQuestionCommand呼叫:

    IQuestionVotingService.VoteUpQuestion(GUID questionId,用戶ID的Guid);

  • 這樣就會產生兩個問題&用戶聚合,在兩者上調用適當的方法,例如user.IncrementReputation(int amount)和question.VoteUp()。這會引發兩個事件; UsersReputationIncreasedEventQuestionUpVotedEvent分別,這將由查詢端處理。

+0

我看到了聚合訂閱事件處理程序的示例,但我認爲它確實使問題複雜化。 – madcapnmckay

+0

我喜歡你提出的解決方案,它類似於Tom建議的解決方案,因爲外部協調器服務執行邏輯。我最初想避免的是聲譽增加的價值。我在解決方案中看到的唯一缺點是,如果我改變了提高問題的聲譽的價值,我不能輕易重新計算(如過去一樣)。根據情況你可能會看到這是一個加分,但我希望能夠重新計算。有趣的是,這引發了許多不同的解決方案(請參閱編輯)。 – madcapnmckay

+1

我不確定您是否必須在活動中增加聲譽增加的金額?投票的價值可能只存儲在查詢端,並且您可以只有一個'UsersQuestionVotedUpEvent'事件,它在處理時查找當前投票的價值,並將該用戶的信譽增加該數額。更改投票的價值將只是更新查詢的一種情況。當然,這隻有在域本身不關心用戶的實際信譽評分時纔有效。 –

0

用戶總應該有一個QuestionAuthored事件......在這種情況下是訂閱到QuestionUpvotedEvent ...同樣它應該有一個QuestionDeletedEvent和/或QuestionClosedEvent以及其中它不妥善處理像是從QuestionUpvotedEvent等unsibscribing

編輯 - 按評論:

我會實現的問題是外部事件源,並通過網關處理它。網關反過來是一個負責處理任何重播正確的,所以最終結果保持完全一樣 - 除了特殊事件,如拒絕事件...

+0

你將如何重播這個來重建事件中的聚集?假設您在聚合上有一個RebuildFromEvents方法。爲了重放,您將獲得用戶ID的所有事件並通過此方法推送它們。在你的描述中,你不會得到和以前一樣的聲譽值... – madcapnmckay

+0

我會將問題作爲「外部事件源」來實現,並通過網關進行處理,而網關又負責處理「重放模式「......這樣的問題描述不會出現 – Yahia

+0

你有任何例子嗎?我看過的每個事件重播都是由聚合處理的。您的方案中的網關是我在編輯中提到的ReputationEventHandler嗎?由於此處理程序最終發送生成用戶事件的命令,因此重播不是問題。處理程序也可以全局訂閱。 – madcapnmckay

2

我的經驗法則:如果你做內部AR通信使用傳奇。它將事物保存在事務邊界內,並使鏈接顯式=>更易於處理/維護。

0

這是舊的問題,並標記爲回答,但我認爲可以添加一些東西。 經過幾個月的閱讀,練習並創建基於CQRS + ES的小型框架和應用程序庫,我認爲CQRS試圖分離組件依賴性和責任。在某些資源中爲每個命令編寫代碼如果在命令處理程序上更改了最大一個聚合(您可以在處理程序上加載多個聚合,但其中只有一個可以更改)。 所以在你的情況下,我認爲最好的做法是@Tom的答案,你應該使用傳奇。如果你的框架不支持傳奇(像我的小框架),你可以創建一些事件處理程序,如UpdateUserReputationByQuestionVotedEvent。其中,處理者創建UpdateUserReputation(Guid user id, int amount)UpdateUserReputation(Guid user id, Guid QuestionId, int amount)UpdateUserReputation(Guid user id, string description, int amount)。在命令發送到處理程序後,處理程序通過用戶標識加載用戶並更新狀態和屬性。在這種類型的處理中,您可以創建更復雜的場景或工作流程。