马上加入IBC程序猿 各种源码随意下,各种教程随便看! 注册 每日签到 加入编程讨论群

C#教程 ASP.NET教程 C#视频教程程序源码享受不尽 C#技术求助 ASP.NET技术求助

【源码下载】 社群合作 申请版主 程序开发 【远程协助】 每天乐一乐 每日签到 【承接外包项目】 面试-葵花宝典下载

官方一群:

官方二群:

NServiceBus+Saga开发分布式应用

[复制链接]
查看2702 | 回复0 | 2019-10-24 09:48:39 | 显示全部楼层 |阅读模式

媒介

当你在处理异步消息时,每个单独的消息处理程序都是一个单独的handler,每个handler之间互不影响。这时如果一个消息依赖另一个消息的状态呢? 这时业务逻辑怎么处理?

094839yrxspdigt4sxriqg.jpg

借用我们上篇文章的业务场景,如果在Ship项目里须要发送一个ShipOrder Command。这个ShipOrder须要依赖Sales.OrderPlaced和Bill.OrderBilled Command的状态,现在我们的两个单独的Message Handler都没有保持任何的状态字段,所以这时如果我们须要完成这个业务模子,就须要跟踪他们的状态。

什么是Saga

这个就是本篇文章要提的saga,界说在NServiceBus框架里,他的本质是一个消息驱动模子里的状态机,或者也可以明白为一系列消息处理程序用来共享状态的业务模子。我明白在消息队列里如果我们要包管消息同等性通常会本身创建一张Event表,这里saga维持状态的脚色有点像我们这里的Event表。

094840bwacyzszl0w7clj0.jpg

好的,回到正题上,如果我们须要在Shipping Service里发送一个ShipOrder,发送他之前须要确定OrderPlaced和OrderBilled的状态,确保这两个消息都收到以后才华发送ShipOrder。

如何利用Saga

固然,我临时明白Saga的目的是为了处理在长时间运行的使命里包管数据同等性如许的一个脚色。

Saga状态

saga状态主要是告诉NServiceBus在处理数据同等性的判定逻辑,这里须要继承抽象类ContainSagaData,在我们这个业务场景中则主要是判定OrderPlaced和OrderBilled消息是否已经吸取到并处理。

  1. <code>public class ShippingPolicyData:ContainSagaData
  2. {
  3. public string OrderId { get; set; }
  4. public bool IsOrderPlaced { get; set; }
  5. public bool IsOrderBilled { get; set; }
  6. }</code>
复制代码

Saga如何工作

有了状态以后,我们还须要一个“handler”来告诉NServiceBus,在这个handler里主要用来处理消息数据同等性,我看了官方文档后,他们建议我们这里的handler脚色利用Policy后缀定名,固然我觉的也可以用Saga后缀定名,比如ShippingPolicy或者ShippingSaga。
同时这里我们这个handler觉色还要继承Saga类,Saga类主要重写方法ConfigureHowToFindSaga,这个方法的作用主要是在继承的消息和我们的Saga实体之间创建映射关系。

  1. <code> public class ShipPolicy:Saga<ShippingPolicyData>,
  2. IAmStartedByMessages<OrderPlaced>,
  3. IAmStartedByMessages<OrderBilled> //都可以创建Saga实例
  4. {
  5. private static ILog log = LogManager.GetLogger<ShipPolicy>();
  6. protected override void ConfigureHowToFindSaga(SagaPropertyMapper<ShippingPolicyData> mapper)
  7. {
  8. mapper.ConfigureMapping<OrderPlaced>(t=>t.OrderId).ToSaga(sagaData=>sagaData.OrderId);
  9. mapper.ConfigureMapping<OrderBilled>(t=>t.OrderId).ToSaga(sagaData=>sagaData.OrderId);
  10. }
  11. public Task Handle(OrderPlaced message, IMessageHandlerContext context)
  12. {
  13. log.Info("OrderPlaced message received ");
  14. this.Data.IsOrderPlaced = true;
  15. return ProcessOrder(context);
  16. }
  17. public Task Handle(OrderBilled message, IMessageHandlerContext context)
  18. {
  19. log.Info("OrderBilled message received");
  20. this.Data.IsOrderBilled = true;
  21. return ProcessOrder(context);
  22. }
  23. private async Task ProcessOrder(IMessageHandlerContext context)
  24. {
  25. if (Data.IsOrderBilled && Data.IsOrderPlaced)
  26. {
  27. await context.SendLocal(new ShipOrder()
  28. {
  29. OrderId = Data.OrderId
  30. });
  31. MarkAsComplete();
  32. }
  33. }
  34. }</code>
复制代码


这个类里你会发现还实现了接口IAmStartedByMessages, 这个接口主要是告诉Saga,岂论是那种消息范例先进来,都可以创建一个Saga实例,就比如是Event表,不管谁人消息进来,都须要先插入一条数据,后续消息再进来时要更新数据状态,固然,这里的Saga实例也好,Event表也好,关键问题就是有效标识,或者叫主键,我们这个业务模子里,OrderPlaced和OrderBilled都包含一个属性OrderId, 这里Saga实例则利用这个OrderId做关键属性。

发送ShipOrder Command

到这里也就是我们的OrderPlaced和OrderBIlled消息都收到了,业务逻辑符合要求,可以发送ShipOrder消息了,也就是用户创建了订单,付了款,可以发货了。

094844sgnvgtkax8s8xozo.jpg

新建ShipOrder类

  1. <code>public class ShipOrder:ICommand
  2. {
  3. public string OrderId { get; set; }
  4. }</code>
复制代码

新建ShipOrderHandler

  1. <code>public class ShipOrderHandler:IHandleMessages<ShipOrder>
  2. {
  3. private static ILog log = LogManager.GetLogger<ShipOrderHandler>();
  4. public Task Handle(ShipOrder message, IMessageHandlerContext context)
  5. {
  6. log.Info($"Order [{message.OrderId}] - Successfully shipped");
  7. return Task.CompletedTask;
  8. }
  9. }</code>
复制代码

运行Shipping项目,看到下图,则说明程序运行乐成,我们这个业务场景里OrderPlaced消息肯定先继承到,OrderBilled消息后继承到。

094845eqhzwlymyyphkh0q.jpg

参考链接

https://docs.particular.net/tutorials/nservicebus-sagas/1-getting-started/
https://docs.particular.net/nservicebus/sagas/







来源:https://www.cnblogs.com/sword-successful/p/11729082.html
C#论坛 www.ibcibc.com IBC编程社区
C#
C#论坛
IBC编程社区
*滑块验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则