簡體   English   中英

采購事件如何更改業務規則

[英]Event-Sourcing how to change business rules

我的應用程序使用cqrs和事件源。 它已經在生產中。 現在,我必須添加業務規則。 我的業務規則在我的聚合根UserAggregate中。

我的命令:

public class CallUserForMarketingPlanCommand 
{
    public Guid UserId {get;set;}
    public DateTime CallDate {get;set;} 
    public Guid PlanId {get;set;}
}

public class AcceptMarketingPlanCommand
{
    public Guid UserId {get;set;}
    public Date AswerDate {get;set;}
    public Guid PlanId {get;set;}
}

... the same thing for RefuseMarketingPlanCommand

這些命令應用於我的聚合根,這些根生成存儲在事件存儲中的事件

現在,如果在通話后50天,用戶不回答,則必須由接線員回撥該用戶。 為此,我認為生成事件UserDoNotRepliedInDelayEvent並將其用於投影到具有召回信息的讀取模型。

我的解決方案是創建一個延遲的命令(從UserCalledForMarketingPlanEvent處理程序)CheckUserAnswerCommand,該命令檢查調用日期並根據需要在聚合中生成UserDoNotRepliedInDelayEvent。 好。

我的問題是如何在已經存在於我的事件存儲中的用戶(在此更改之前)上延遲此命令?

編輯:

在不考慮延遲消息的情況下,如何更改影響聚合狀態的業務規則(或業務規則參數)。 簡單的例子:

如果未執行兩次付款,請禁用帳戶。

這條規則是第一次部署的。 好的,現在有1000個帳戶已禁用。 老板更改規則是因為業務受到影響,如果未執行5次付款,則要禁用帳戶。

如何啟用少於5次付款的帳戶?

謝謝你的幫助。

現在,如果在通話后50天,用戶不回答,則必須由接線員回撥該用戶。 為此,我認為生成事件UserDoNotRepliedInDelayEvent並將其用於投影到具有召回信息的讀取模型。

如果我正確地理解了您的問題,那么這里的主要觀點是,及時“不回復”的用戶不是您所在域的操作(命令),相反,這是因為沒有操作。 因此,在這種情況下,我認為您根本不需要任何事件。

您只需要一個讀取模型,該模型將注冊所有已發送的邀請及其狀態(是否得到答復,答復日期以及未答復的時間)。 然后,您可以檢查此讀取模型中是否有超過您的50天期限的未答復邀請(此時應足夠簡單)。

因此,到目前為止,“邀請”事件存儲中未生成新事件。 您只是將商店解釋為特定的讀取模型,該模型將回答您所遇到的問題(未答復哪些邀請)。

從這一點來看,這取決於您的體系結構。

  • 您可能需要一個周期性的過程來檢查此讀取模型是否有超過您的截止期限的邀請,讓這些特定的邀請觸發“ InvitationExpiredEvent”或通知有興趣的各方(例如,將重發這些消息的一方)

  • 或者,您可能只是想要一種更被動的方法,而不需要額外的事件,只需在適當時(也許在GUI上)讀取此Read Model並列出過期的邀請即可。

然后,這將自行修復...因為您可以追溯生成讀取模型(從永遠無法回答其邀請的任何給定點查找用戶),然后將他們置於重新邀請管道中。

在不考慮延遲消息的情況下,如何更改影響聚合狀態的業務規則(或業務規則參數)。 簡單的例子:

如果未執行兩次付款,請禁用帳戶。

這條規則是第一次部署的。 好的,現在有1000個帳戶已禁用。 老板更改規則是因為業務受到影響,如果未執行5次付款,則要禁用帳戶。

如何啟用少於5次付款的帳戶?

您的問題的這一部分更加令人困惑。 據我了解,您曾經有一條規則規定“應停用兩個或多個過期付款的帳戶”,而您想將此規則更改為“應停用五個或多個過期付款的帳戶”。 如果是這樣,您必須在多個層面上解決這個問題...

  • 首先,您必須首先在命令模型上實施新規則,就像過去一樣,只是使用更新的參數。

  • 其次,您無法通過忽略其“停用事件” 追溯重新激活具有2,3,4個過期付款的帳戶。 從事件存儲的角度來看,這發生了,您必須遵守規則,即事件存儲是“僅推送”存儲 因此,您必須使用補償事件在規則更改后重新激活它們。

因此,如果您處理了第一個主題(並且您的域已按照新規則啟動並運行),並且由於第二個主題而無法使用快捷方式,那么您更容易選擇的方法之一就是簡單地開發一個主題,射擊操作將查找具有2,3,4的當前已禁用的過期付款並添加到其事件的帳戶存儲重新激活事件。 此時,如果您的架構不能自動執行此操作,則必須重新生成所有受影響的讀取模型。

這樣,下次針對這些帳戶執行命令時,它們的事件存儲將反映出它們已被重新激活並因此當前處於活動狀態的事實。

從事件存儲的角度來看...這些帳戶中的每個帳戶在其事件流上都會有類似的內容:

...>付款已過期>帳戶已禁用>(也許發生了其他事情)>帳戶已重新啟用

因此,您的事件存儲區將非常准確地表示您的業務情景...一旦您選擇禁用僅具有2個過期付款的帳戶,因此某個帳戶已被禁用...后來您改變了主意,甚至沒有付款他們的債務,這些帳戶被重新啟用。

編輯:

實際上,我認為可以通過“如何在事件源系統中集成追溯規則”來概括該問題。

如果是這樣,那么答案將更多地側重於“在事件源域中不應有追溯行動”。

正如我在原始答案中所說的那樣,事件流應該是“僅推送”存儲,這主要是因為只有事件發生時的確切順序才能保證規則的完整性,就像事件發生時一樣。 從這種意義上講,事件存儲比傳統的存儲更不靈活,因為它對外部干擾更敏感,有時會很痛苦(習慣於直接干預數據源以修復問題)。

但是,我們應該真正遵守規則,並承認發生的任何事情,發生的事情以及無法更改的事情。 您可以做的是在事件流“補償事件”的末尾添加新事件,這些新事件將在給定時間記錄狀態變化以反映您的規則更改。 然后,您將需要一個步驟即可遍歷您的實體,並確定其中哪些實體有資格進行此類補償事件。

現在,當然,在需要時可以打破規則,並且經過充分考慮,您可以瘋狂進入事件存儲。 只知道風險。 如果您選擇進入“全職機器模式”進入事件存儲,那么您將面臨(並且應避免)的主要風險是:

  • 實體在其生命周期內進入無效狀態。 實體以有效狀態“結束”事件流並不重要。 您必須驗證它永遠不會進入無效狀態,因為這是事件流的先決條件。 因此,對於受編輯影響的每個實體,您將需要在新事件流中逐步評估其有效性。

  • 源代碼和事件流之間不匹配。 這有點棘手。 但是,事件源系統可以執行的操作之一是將源代碼存儲庫回滾到給定日期,並從該日期開始“丟棄”事件。 這樣,您可以像過去一樣重新執行動作。 但是,如果您編輯過去的事件,則可能會遇到這樣的情況,即根據源代碼記錄的事件與過去發生的事件不匹配。 將來這可能很關鍵,而且極有誤導性。 您應該監視它。

  • 如果您的架構集成了不同的上下文/域/微服務,則可能還需要進一步評估。 假設由於實體的給定狀態,上下文A向上下文B發布了跨邊界消息。 繼續前進,您可以通過干預事件流來更改實體狀態。 現在,由於上下文B認為實體具有它不再具有的狀態,因此這些上下文之間可能會不一致。 這可能與您的情況非常相關。

您還可以使用Saga來跟蹤流程,並在時間到時創建諸如“ recallneeded”之類的命令。 它還會跟蹤事件,這些事件告訴Saga在50天內是否接到電話。 (請記住,傳奇是域邏輯的一部分,如果執行DDD,則充當AR)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM