Domain driven design 容错及;域服务中的状态管理

Domain driven design 容错及;域服务中的状态管理,domain-driven-design,Domain Driven Design,在我的域中,服务用于协调涉及多个聚合和/或其他服务的更高级别行为。例如,订单管理系统在取消订单时需要执行以下步骤: 将订单状态更改为“已取消” 撤销任何未决的信用卡交易 添加包含订单取消原因解释的审核条目 将对订单的更改保留到数据存储 引发OrderCanceledEvent(作为消息) 编码这是非常简单的,除了我还需要实现一些额外的关注点: 如果订单不在状态,我无法执行任何操作 “可取消”状态 如果当前用户没有权限,我无法执行任何操作 取消订单的权限 如果我不能撤销信用卡交易,那么整个 操作

在我的域中,服务用于协调涉及多个聚合和/或其他服务的更高级别行为。例如,订单管理系统在取消订单时需要执行以下步骤:

  • 将订单状态更改为“已取消”
  • 撤销任何未决的信用卡交易
  • 添加包含订单取消原因解释的审核条目
  • 将对订单的更改保留到数据存储
  • 引发OrderCanceledEvent(作为消息)
  • 编码这是非常简单的,除了我还需要实现一些额外的关注点:

    • 如果订单不在状态,我无法执行任何操作 “可取消”状态
    • 如果当前用户没有权限,我无法执行任何操作 取消订单的权限
    • 如果我不能撤销信用卡交易,那么整个 操作应失败,订单应保持其原始状态 陈述
    • 添加审核条目失败不会中止操作
    • 如果未能持久保存订单,则应中止该操作和订单 应保持其原始状态
    只有步骤1、2和4成功,操作才会成功。因此,我无法将这些步骤作为事件处理程序实现

    抛开使用中的持久性机制的任何问题(它是什么),您能否帮助我了解如何最好地实现我的服务,以便它能够正确地处理验证、错误和管理订单状态


    (我应该注意,我没有使用事件源,所以不要让OrderCanceledEvent抛出您。)

    使用事件处理程序解决此问题的一种方法是使用事件源。工作流程如下:

    • 收到
      CancelOrder
      命令后,启动
      OrderCancellationSaga
      ,将订单置于
      取消
      状态
    • 在支付网关确认退款后,该传奇即告完成,订单处于取消状态并持续。此时,在同一事务中,将引发
      OrderCancelled
      事件

    • 如果与支付网关的交互失败或被拒绝,订单可以恢复到先前的状态或进入某种错误状态
    在这种情况下,审计可以在任何阶段进行。此外,在开始传奇之前,或者作为开始传奇的第一步,应该首先验证权限以及是否可以取消订单

    带有C#和sagas的粗糙样品:

    class OrderCancellationSaga:Saga
    ,我开始,
    ,我处理
    {
    公共医嘱服务{get;set;}
    公共付费网关付费网关{get;set;}
    //按订单ID关联saga消息
    公共覆盖无效配置HowtoFindsaga()
    {
    配置映射(x=>x.OrderId,x=>x.OrderId);
    配置映射(x=>x.OrderId,x=>x.OrderId);
    }
    //启动取消流程
    公共无效句柄(CancelOrderCommand消息)
    {
    //检查取消是否授权且有效
    // ....
    //如果需要,可以在此保存以前的状态
    this.Data.OrderId=message.OrderId;
    this.Data.State=“取消”;
    this.Bus.Send(新命令(…);
    }
    公共无效句柄(ReturnCompletedEvent消息)
    { 
    this.Data.State=“已取消”;
    这个.OrderService.CompleteCancellation(…);
    MarkAsComplete();
    }
    //此处理程序可以托管在不同的端点上。
    公共无效句柄(RETURNORDER命令消息)
    { 
    尝试
    {
    此.PaymentGateway.Return(。。。
    }
    捕获(例外情况除外)
    {
    this.Bus.Reply(新的PaymentGatewayInteractionFailedEventmessage(…);
    }
    }
    //此处理程序可用于还原整个操作。
    公共无效句柄(PaymentGatewayInteractionFailedEvent消息)
    {
    //或者恢复到先前的状态。
    this.Data.Status=“取消失败”;
    //调用任何需要的应用程序服务。
    //结束传奇,删除状态
    MarkAsComplete();
    }
    }
    
    根据我对Sagas的了解,它们通常被实现为域服务或命令处理程序,这正是我正在做的。我也在寻找一些更具体的东西(带有代码示例)来说明如何做到这一点。例如,顺序是如何恢复的?(请记住,正如我在更新中指出的,我没有使用事件源。)是的,sagas只是将状态与通过某个键关联的消息关联起来的消息处理程序。sagas与事件源正交。例如,您使用的是什么语言/平台?如果与支付网关的交互失败,则订单可以进入任何状态。此状态可以有效地“恢复”cancel操作很有趣。很遗憾,我们没有使用NServiceBus,因此实现并不完全合适,但我将进一步回顾。不管怎样,saga模式应该适用,NServiceBus只是一个实现。
    class OrderOrderCancellationSaga : Saga<OrderCancellationSagaData>
      ,IAmStartedBy<CancelOrderCommand>,
      ,IHandle<PaymentGatewayInteractionFailedEvent> 
    {
    
      public OrderService OrderService { get; set; }
      public PaymentGateway PaymentGateway { get; set; }
    
     // correlate saga messages by order ID  
     public override void ConfigureHowToFindSaga()
     {
          ConfigureMapping<PaymentGatewayInteractionFailedEvent>(x => x.OrderId, x =>x.OrderId);
          ConfigureMapping<RefundCompletedEvent>(x => x.OrderId, x => x.OrderId);
     }
    
      // start cancellation process
      public void Handle(CancelOrderCommand message) 
      {
         // check if cancellation is authorized and valid
         // ....
    
         // can save prior state here, if needed
    
         this.Data.OrderId = message.OrderId;
         this.Data.State = "Cancelling";    
    
    
         this.Bus.Send(new RefundOrderCommand(...));
      }
    
      public void Handle(RefundCompletedEvent message)
      { 
         this.Data.State = "Cancelled"; 
         this.OrderService.CompleteCancellation(...);                 
         MarkAsComplete();
      }
    
      // this handler can be hosted on a different endpoint.
      public void Handle(RefundOrderCommand message)
      { 
         try
         {
            this.PaymentGateway.Refund(...
         }
         catch(Exception ex)
         {
            this.Bus.Reply(new PaymentGatewayInteractionFailedEventmessage(...));
         }
      }
    
      // this handler can be used to revert whole operation.
      public void Handle(PaymentGatewayInteractionFailedEvent message)
      {
         // or revert to prior state.
         this.Data.Status = "Cancellation Failed";
    
         // call any application services needed.
    
         // finishes saga, deleting state
         MarkAsComplete();
      }
    
    }