同步命令/事件处理程序的事务范围(在NServiceBus中)

时间:2014-04-08 20:38:55

标签: transactions domain-driven-design nservicebus

假设我们有以下业务规则:

  1. 当订单被取消时,所有未发货的货物应该是 取消。
  2. 个别货件可能因其他原因被取消。
  3. 如果我们同步这样做,我对交易范围有疑问:

    1. 我听说它说Aggregate ==“transactional boundary”,但在这种情况下请求范围DbContext不是更有利于所有同步处理程序在同一个事务中执行吗?如果后两个处理程序出现故障,它会提供更多的一致性。
    2. 如果#1不是个好主意,为什么?我们只是说“自己的交易中的每个处理程序,如果在它的中间出现问题,你就是自己的”?
    3. 如果#1是个好主意,我该如何使用NServiceBus'Bus.InMemory执行此操作? The documentation在这件事上并不十分清楚。
    4. 代码如下:

      public class CancelOrder : ICommand 
      {
          public Guid Id { get; set; }
      }
      
      public class OrderCancelled : IEvent
      {
          public Guid Id { get; set; }
      }
      
      public class CancelShipment : ICommand
      {
          public Guid Id { get; set; }
      }
      
      public class CancelOrderHandler : IHandleMessages<CancelOrder>
      {
          private DbContext _dbContext;
          private IBus _bus;
      
          public void Handle(CancelOrder message) 
          {
              var order = _dbContext.Orders.Single(x => x.Id == message.Id);
      
              // do some validation here
      
              order.Status = OrderStatus.Cancelled;
      
              // unsure about whether to call _dbContext.SaveChanges() or not
      
              _bus.Publish(new OrderCancelled {
                  Id = message.Id
              });
          }
      }
      
      public class OrderCancelledHandler : IHandleMessages<OrderCancelled>
      {
          private DbContext _dbContext;
          private IBus _bus;
      
          public void Handle(CancelOrder message) 
          {
              var commands = _dbContext.Shipments
                  .Where(x => x.OrderId == message.Id && x.Status != ShipmentStatus.Shipped)
                  .Select(x => new CancelShipment {
                      Id = x.Id
                  });
      
              _bus.Send(commands);
          }
      }
      
      public CancelShipmentHandler : IHandleMessages<CancelShipment>
      {
          private DbContext _dbContext;
      
          public void Handle(CancelShipmentHandler message) 
          {
              // Similar to CancelOrder, only with shipments.
          }
      }
      

1 个答案:

答案 0 :(得分:3)

这里的答案取决于业务要求 - 例如,如果我们无法取消其中一个货件,这是否意味着我们应该取消订单的取消?

我的感觉是答案可能不是。因此,您使用的消息驱动模型似乎比在单个处理程序中同步执行所有操作更合适。

我对您的代码的一个小问题是您在OrderCancelledHandler中发布命令。你可能应该Bus.Send他们。

此外,通过执行单个Bus.Publish / Bus.Send,您指示完整命令集的处理应该是一个事务。我不认为你想要那个。相反,我建议循环执行命令并分别为每个命令执行Bus.Send。