我很努力地通過重播來自EventStore的事件來重建模型時發生的事情,特別是當事件可能觸發其他事件時。事件源:觸發他人和重建狀態的事件
例如,已經進行了10次購買的用戶應該被推薦給優先顧客並且接收提供他們特定促銷的電子郵件。
我們顯然不希望每次爲該用戶重建模型時都會發送電子郵件,但是當我們重播我們的第10個PurchaseMadeEvent
時,我們該如何阻止這種情況發生?
我很努力地通過重播來自EventStore的事件來重建模型時發生的事情,特別是當事件可能觸發其他事件時。事件源:觸發他人和重建狀態的事件
例如,已經進行了10次購買的用戶應該被推薦給優先顧客並且接收提供他們特定促銷的電子郵件。
我們顯然不希望每次爲該用戶重建模型時都會發送電子郵件,但是當我們重播我們的第10個PurchaseMadeEvent
時,我們該如何阻止這種情況發生?
事件鏈可能非常棘手,很容易失控,所以我會盡量避免它。例如,在您描述的情況下,我會提出一個UserPromotedEvent
(甚至可能使用PromoteUserCommand
),但是我不會將電子郵件的實際/實際發送作爲我的域的一部分。相反,我會爲UserPromotedEvent
創建額外的處理程序/去標準化程序,它將註冊發送電子郵件的必要性,並且很可能會進行一些額外的檢查。之後,另一個流程將收集尚未處理的電子郵件的信息併發送。這種方法可以緩解不完全可訪問/可擴展的電子郵件網關可能出現的問題。
更一般而言 - 事件鏈接的需要經常表明您應該考慮爲該流程實施Saga。
當您重放事件時,您沒有重放生成這些事件的所有域邏輯。通常在你的域名方法中,你會引發一個事件;那麼提升該事件應該更新該域對象的整體狀態。
例如:
public class Purchase {
private int _id;
private string _name;
private string _address;
private double _amount;
public Purchase(int id, string name, string address) {
//do some business rule checking to determine if event is raised
//perhaps send an email or do some logging
//etc.
if (should_i_raise_event) {
ApplyEvent(new PurchaseMadeEvent() {
ID = id,
Name = name,
Address = address
});
}
}
public UpdatePurchase(int id, double amount) {
//more checking to see if event is to be raised
if (should_i_raise_event) {
ApplyEvent(new PurchaseUpdatedEvent() {
ID = id,
Amount = amount
});
}
}
protected void OnPurchaseMade(PurchaseMadeEvent e){
_id = e.ID;
_name = e.Name;
_address = e.Address;
}
protected void OnPurchaseUpdated(PurchaseUpdatedEvent e){
_id = e.ID;
_amount = e.Amount;
}
}
在這個例子中,當我的事件重演,在OnPurchaseMade
事件處理程序將得到執行,而不是域對象的構造函數。與PurchaseUpdatedEvent
相同 - 它的事件處理程序將被執行,而不是引發事件的域方法。
事件包含您需要更新域模型的所有內容(並將更新應用於讀取模型)。獲得執行的域方法可以讓您注意到可以引發事件。
我希望這會有所幫助。讓我知道是否需要提供更多信息。
祝你好運!
你不應該從事件處理程序引發事件 - 只是不要這樣做!您應該改用sagas。
在你的情況,傳奇訂閱PurchaseMadeEvent
和問題PromoteCustomer
命令,這導致發生CustomerPromoted
事件。再次,有另一個傳奇訂閱CustomerPromoted
事件併發送SendEmailToPromotedCustomer
命令。當你正在重播事件時 - 只要不訂閱CustomerPromoted
事件的傳奇。
這是關於命令和事件之間的區別。理解它很重要。事件告訴已經發生了什麼,命令告訴會發生什麼。
我意識到這是一個非常古老的答案,但是,佐賀如何知道當它收到一個'PurchaseMadeEvent'時發出'PromoteCustomer'命令?這依賴於(根據OP的描述)客戶做了10次購買,這是佐賀不應包含的域邏輯。也許總是激發一個'TestToPromoteCustomer'並讓聚合體做檢查來實際進行升級?這雖然感覺有點笨拙..感謝任何洞察 –
是的,你說的對,傳奇應該發送TestToPromoteCustomer命令。我認爲爲了可維護性而犧牲純度絕對沒問題。 – xelibrion