2016-08-19 64 views
0

微軟服務和CQRS事件處理的新手。我想通過一個簡單的任務來理解。在這個任務中,我有三個REST外部服務來處理一個事務/請求(服務)。這三個服務是CQRS甚至可以在哪裏調用SagaManager

step1:客戶創建。

第2步:爲客戶創建業務

第3步:爲業務創建地址。

我想用InMemorySagaRepository和saga manager來實現這些事件的SAGA。

在哪裏我必須啓動存儲庫的SagaManager,它在RestController或CommandHandler中?

你能幫我理解傳奇流嗎?

在此先感謝。

+0

歡迎來到堆棧溢出。你可以改善你的問題。請閱讀[如何提問](http://stackoverflow.com/help/how-to-ask),其中包括「如何以智能方式提問」鏈接。 – zhon

+0

我們在工作中使用事件採購和CQRS。我們發現'傳奇'對不同的人來說意味着不同的事物。所以我只是想澄清一下:你對傳奇的意義是什麼?鏈接到你閱讀的地方會有很大的幫助,所以我們知道你在問什麼。 – Chewtoy

回答

0

一種方法可能是啓動Saga的某種啓動命令。在這種情況下,它將在您的組合根中進行配置,以偵聽特定的命令類型。一旦在你的消息調度程序中接收到一個命令(或者你擁有的任何中間件消息),它就會查找已經註冊的由命令啓動的任何Sagas。然後你會創建佐賀並傳遞命令。它可以在發生時響應其他命令和事件。

在你的情況我建議你佐賀一種命令處理程序因此它的啓動將在半年後接收命令

+0

感謝您的快速回復。我的主要服務是調用其他三項服務。如果沒有錯,我必須在主要服務中發起我的傳奇。 – user1386039

2

,和我」我做編輯我現在已經參加了Greg Young舉辦的一個叫的課程。Greg Young的CQRS,域名事件,事件採購以及如何申請DDD 我真的會把它推薦給任何想到CQRS的人。有很大的幫助,瞭解哪些東西其實都是


原始anwser

在我們的產品,我們使用的傳奇故事爲一些反應事件。 這意味着我們的傳奇真的只是特定活動的訂閱者。然後這個傳奇對於它是否應該做某事持有一些邏輯。 如果事件發現應採取行動,它會創建一個命令,將其放在CommandBus上。 這意味着Sagas只是'反應器',並且與用戶使用相同的路徑(跳過API等)。

但佐賀真的是什麼,它應該做什麼,不同於向另一方談論他們。 (免責聲明:這是我如何閱讀這些帖子,他們可能實際上都說同樣的事情,但以一種蓬鬆的方式[我的團隊]看到這一點)

http://blog.jonathanoliver.com/cqrs-sagas-with-event-sourcing-part-i-of-ii/例如,提出了點薩加斯不應該包含'業務邏輯'(任何包含'如果'是根據職位的業務邏輯)。

https://msdn.microsoft.com/en-us/library/jj591569.aspx談到薩加斯作爲'進程管理器',協調不同的聚合之間的事情(記住,Aggregate1不能直接與Aggregat2交談,所以需要一個'進程管理器'來協調溝通)。簡單地說:事件 - >佐賀 - >命令 - >事件 - >佐賀...到達最終目的地。

https://lostechies.com/jimmybogard/2013/03/21/saga-implementation-patterns-variations/會談的傳奇是關於什麼的兩種不同的模式。一個是'Publish-gatherer',它基本上根據Command來協調應該發生的事情。另一個是「記者」,它只是將事情的狀態報告給他們需要去的地方。它不協調事情,它只是報告需要報告的任何事情。

http://kellabyte.com/2012/05/30/clarifying-the-saga-pattern/有什麼樣的傳奇模式「是」一個寫了。聲稱薩加斯應該/可以彌補不同的工作流程。

http://cqrs.nu/Faq/sagas有什麼傳奇故事是一個非常簡短的描述,基本上說,「他們是國家機器,讓骨料反應,其他集合體」。

因此,鑑於這種情況,它是什麼你真正想要的傳奇呢?它應該協調一切嗎?還是應該只是作出反應,而不在乎集料的作用?


我編輯的零件

因此,承擔CQRS課程,並與格雷格這個談話後,我得出的結論是,有相當多的困惑在那裏的網頁。

讓我們從「傳奇」這個概念開始。傳奇實際上與CQRS無關。這不是一個概念。 「傳奇」兩階段提交,只有它是成功的優化,而不是失敗(https://en.wikipedia.org/wiki/Compensating_transaction

現在,大多數人意味着當他們談論CQRS,並說「傳奇」是「進程管理器」的一種形式。流程管理者看起來相當複雜(Greg對於流程管理者來說只有一門課程)。 基本上他們所做的是管理某件事的整個過程(顧名思義)。與微軟的聯繫幾乎就是它的全部內容。

要回答這個問題:

確切位置在哪裏我要開始SagaManager與存儲庫,它是在RestController或CommandHandler?

之外他們兩個的。 A 進程管理器是它自己的東西。它跨越集合和存儲庫。從概念上來說,最好把它看作是一個用戶,在做你想做的所有事情,只要你編程用戶交互並告訴它聽什麼。

免責聲明:我不爲格雷格工作,或任何在我的升學課程中取得成績的學生。這只是我從中學到了很多東西,所以我推薦它,就像我推薦閱讀Eric Evans關於DDD的書。

+0

感謝您的快速響應。我的要求是協調服務/事件。 – user1386039

+0

@ user1386039我認爲你的意思是協調,因爲它將錯綜複雜地涉及聚集體的行爲。另一種選擇('反應堆')並不真正在意聚合物是如何的。你想要傳奇以防止事件發生?這意味着在Command層完成所有的工作,或者讓Saga以某種方式阻止事件發佈。 – Chewtoy

+0

@Chewtoy你採取了什麼課程? –

0

在我的應用程序,我使用this MSDN文檔建立佐賀進程管理器,我的佐賀是應用服務層實現,它監聽銷售活動,倉庫&開票界的背景和事件發生通過服務總線發送命令。

簡單的例子,希望它可以幫助你分析如何建立你的傳奇故事(我註冊的傳奇在Composition Root處理);):

SAGA:

public class SalesSaga : Saga<SalesSagaData>, 
    ISagaStartedBy<OrderPlaced>, 
    IMessageHandler<StockReserved>, 
    IMessageHandler<PaymentAccepted> 
{ 
    private readonly ISagaPersister storage; 
    private readonly IBus bus; 

    public SalesSaga(ISagaPersister storage, IBus bus) 
    { 
     this.storage = storage; 
     this.bus = bus; 
    } 

    public void Handle(OrderPlaced message) 
    { 
     // Send ReserveStock command 
     // Save SalesSagaData 
    } 

    public void Handle(StockReserved message) 
    { 
     // Restore & Update SalesSagaData 
     // Send BillCustomer command 
     // Save SalesSagaData 
    } 
    public void Handle(PaymentAccepted message) 
    { 
     // Restore & Update SalesSagaData 
     // Send AcceptOrder command 
     // Complete Saga (Dispose SalesSagaData) 
    } 
} 

InMemorySagaPersister: (因爲SalesSagaDataID我使用OrderID其唯一跨整個過程)

public sealed class InMemorySagaPersister : ISagaPersister 
{ 
    private static readonly Lazy<InMemorySagaPersister> instance = new Lazy<InMemorySagaPersister>(() => new InMemorySagaPersister()); 

    private InMemorySagaPersister() 
    { 
    } 

    public static InMemorySagaPersister Instance 
    { 
     get 
     { 
      return instance.Value; 
     } 
    } 

    ConcurrentDictionary<int, ISagaData> data = new ConcurrentDictionary<int, ISagaData>(); 

    public T GetByID<T>(int id) where T : ISagaData 
    { 
     T value; 
     var tData = new ConcurrentDictionary<int, T>(data.Where(c => c.Value.GetType() == typeof(T)) 
      .Select(c => new KeyValuePair<int, T>(c.Key, (T)c.Value)) 
      .ToArray()); 

     tData.TryGetValue(id, out value); 
     return value; 
    } 

    public bool Save(ISagaData sagaData) 
    { 
     bool result; 

     ISagaData existingValue; 
     data.TryGetValue(sagaData.Id, out existingValue); 
     if (existingValue == null) 
      result = data.TryAdd(sagaData.Id, sagaData); 
     else 
      result = data.TryUpdate(sagaData.Id, sagaData, existingValue); 

     return result; 
    } 

    public bool Complete(ISagaData sagaData) 
    { 
     ISagaData existingValue; 
     return data.TryRemove(sagaData.Id, out existingValue); 
    } 
}