前言
當你在處理異步訊息時,每個單獨的訊息處理程式都是一個單獨的handler,每個handler之間互不影響,這時如果一個訊息依賴另一個訊息的狀態呢? 這時業務邏輯怎么處理?

借用我們上篇文章的業務場景,如果在Ship專案里需要發送一個ShipOrder Command,這個ShipOrder需要依賴Sales.OrderPlaced和Bill.OrderBilled Command的狀態,目前我們的兩個單獨的Message Handler都沒有保持任何的狀態欄位,所以這時如果我們需要完成這個業務模型,就需要跟蹤他們的狀態,
什么是Saga
這個就是本篇文章要提的saga,定義在NServiceBus框架里,他的本質是一個訊息驅動模型里的狀態機,或者也可以理解為一系列訊息處理程式用來共享狀態的業務模型,我理解在訊息佇列里如果我們要保證訊息一致性通常會自己創建一張Event表,這里saga維持狀態的角色有點像我們這里的Event表,

好的,回到正題上,如果我們需要在Shipping Service里發送一個ShipOrder,發送他之前需要確定OrderPlaced和OrderBilled的狀態,確保這兩個訊息都收到以后才能發送ShipOrder,
如何使用Saga
當然,我暫且理解Saga的目的是為了處理在長時間運行的任務里保證資料一致性這樣的一個角色,
Saga狀態
saga狀態主要是告訴NServiceBus在處理資料一致性的判斷邏輯,這里需要繼承抽象類ContainSagaData,在我們這個業務場景中則主要是判斷OrderPlaced和OrderBilled訊息是否已經接收到并處理,
public class ShippingPolicyData:ContainSagaData
{
public string OrderId { get; set; }
public bool IsOrderPlaced { get; set; }
public bool IsOrderBilled { get; set; }
}
Saga如何作業
有了狀態以后,我們還需要一個“handler”來告訴NServiceBus,在這個handler里主要用來處理訊息資料一致性,我看了官方檔案后,他們建議我們這里的handler角色使用Policy后綴命名,當然我覺的也可以用Saga后綴命名,比如ShippingPolicy或者ShippingSaga,
同時這里我們這個handler覺色還要繼承Saga
public class ShipPolicy:Saga<ShippingPolicyData>,
IAmStartedByMessages<OrderPlaced>,
IAmStartedByMessages<OrderBilled> //都可以創建Saga實體
{
private static ILog log = LogManager.GetLogger<ShipPolicy>();
protected override void ConfigureHowToFindSaga(SagaPropertyMapper<ShippingPolicyData> mapper)
{
mapper.ConfigureMapping<OrderPlaced>(t=>t.OrderId).ToSaga(sagaData=https://www.cnblogs.com/sword-successful/p/>sagaData.OrderId);
mapper.ConfigureMapping(t=>t.OrderId).ToSaga(sagaData=>sagaData.OrderId);
}
public Task Handle(OrderPlaced message, IMessageHandlerContext context)
{
log.Info("OrderPlaced message received ");
this.Data.IsOrderPlaced = true;
return ProcessOrder(context);
}
public Task Handle(OrderBilled message, IMessageHandlerContext context)
{
log.Info("OrderBilled message received");
this.Data.IsOrderBilled = true;
return ProcessOrder(context);
}
private async Task ProcessOrder(IMessageHandlerContext context)
{
if (Data.IsOrderBilled && Data.IsOrderPlaced)
{
await context.SendLocal(new ShipOrder()
{
OrderId = Data.OrderId
});
MarkAsComplete();
}
}
}
這個類里你會發現還實作了介面**IAmStartedByMessages
發送ShipOrder Command
到這里也就是我們的OrderPlaced和OrderBIlled訊息都收到了,業務邏輯符合要求,可以發送ShipOrder訊息了,也就是用戶創建了訂單,付了款,可以發貨了,

新建ShipOrder類
public class ShipOrder:ICommand
{
public string OrderId { get; set; }
}
新建ShipOrderHandler
public class ShipOrderHandler:IHandleMessages<ShipOrder>
{
private static ILog log = LogManager.GetLogger<ShipOrderHandler>();
public Task Handle(ShipOrder message, IMessageHandlerContext context)
{
log.Info($"Order [{message.OrderId}] - Successfully shipped");
return Task.CompletedTask;
}
}
運行Shipping專案,看到下圖,則說明程式運行成功,我們這個業務場景里OrderPlaced訊息肯定先接受到,OrderBilled訊息后接受到,

參考鏈接
https://docs.particular.net/tutorials/nservicebus-sagas/1-getting-started/
https://docs.particular.net/nservicebus/sagas/
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/101935.html
標籤:.NET Core
