处理 MassTransit 中的域错误

bie*_*000 3 c# masstransit microservices

我想知道应该如何以正确的方式处理域异常?

我的所有消费者代码是否都应该包装到 try、catch 块中,或者我应该抛出一个异常,该异常将由适当的FaultConsumer 处理?

考虑这两个示例:

示例 1 - 整个操作被包装到 try...catch 块中。

public async Task Consume(ConsumeContext<CreateOrder> context)
{         

try
{
  //Consumer that creates order 
  var order = new Order();
  var product = store.GetProduct(command.ProductId); // check if requested product exists

  if (product is null)
  {
    throw new DomainException(OperationCodes.ProductNotExist);
  }

  order.AddProduct(product);
  store.SaveOrder(order);

  context.Publish<OrderCreated>(new OrderCreated
  {
    OrderId = order.Id;
  });
}
catch (Exception exception)
{
  if (exception is DomainException domainException)
  {
    context.Publish<CreateOrderRejected>(new CreateOrderRejected
    {
      ErrorCode = domainException.Code;
    });
  }                
 }
}
Run Code Online (Sandbox Code Playgroud)

示例 2 - MassTransit 通过将消息推送到 CreateOrder_error 队列来处理 DomainException。另一个服务订阅该事件,并在该事件发布到该特定队列上后对其进行处理;

public async Task Consume(ConsumeContext<CreateOrder> context)
{         

  //Consumer that creates order 
  var order = new Order();
  var product = store.GetProduct(command.ProductId); // check if requested product exists

  if (product is null)
  {
    throw new DomainException(OperationCodes.ProductNotExist);
  }

  order.AddProduct(product);
  store.SaveOrder(order);

  context.Publish<OrderCreated>(new OrderCreated
  {
    OrderId = order.Id;
  });
}
Run Code Online (Sandbox Code Playgroud)

哪种方法应该更好?

我知道我可以使用请求/响应并立即获取有关错误的信息,但就我而言,它必须通过消息代理完成。

Chr*_*son 5

在您的第一个示例中,您通过生成未知产品订单被拒绝的事件来处理域条件(在您的示例中,目录中不存在产品)。这是完全有道理的。

现在,如果用于检查产品的数据库查询无法连接到数据库,这是一种临时情况,可能会自行解决,因此使用重试或计划重新交付是有意义的 - 在完全放弃之前重试。这些是您想要抛出的异常。

但是您想要捕获并通过发布事件来处理的业务异常。

public async Task Consume (ConsumeContext<CreateOrder> context) {

  try {
    var order = new Order ();
    var product = store.GetProduct (command.ProductId); // check if requested product exists
    if (product is null) {
      throw new DomainException (OperationCodes.ProductNotExist);
    }

    order.AddProduct (product);
    store.SaveOrder (order);

    context.Publish<OrderCreated> (new OrderCreated {
      OrderId = order.Id;
    });
  } catch (DomainException exception) {
    await context.Publish<CreateOrderRejected> (new CreateOrderRejected {
      ErrorCode = domainException.Code;
    });
  }
}
Run Code Online (Sandbox Code Playgroud)