Rebus 8下IErrorHandler获取内部异常及优化上报方案咨询
Rebus 8 错误消息上报优化及内部异常获取方案
一、正确获取内部异常信息
Rebus 8 中的 ExceptionInfo 提供了结构化的异常链信息,无需通过字符串匹配判断异常类型:
- 每个
ExceptionInfo实例的Type属性存储了异常的完整类型全名(如System.InvalidOperationException),类型匹配精准可靠; Inner属性对应原异常的InnerException,可通过遍历该属性链获取所有嵌套异常。
示例代码(检查异常链中是否包含目标类型):
private bool ContainsTargetException(ExceptionInfo exceptionInfo, string targetExceptionFullTypeName) { var currentExceptionInfo = exceptionInfo; while (currentExceptionInfo != null) { if (string.Equals(currentExceptionInfo.Type, targetExceptionFullTypeName, StringComparison.Ordinal)) { return true; } currentExceptionInfo = currentExceptionInfo.Inner; } return false; }
使用时传入目标异常的完整类型名(如MyProject.Exceptions.PaymentFailedException)即可,完全替代不可靠的字符串匹配逻辑。
二、更优的失败消息上报实现方案
方案1:复用 IErrorHandler 并适配 ExceptionInfo
如果仍需处理毒消息(多次失败后进入死信的消息),可基于 IErrorHandler 结合上述异常类型检查逻辑实现:
public class SlackErrorHandler : IErrorHandler { private readonly ISlackNotificationService _slackService; public SlackErrorHandler(ISlackNotificationService slackService) { _slackService = slackService; } public async Task HandlePoisonMessage(ErrorInfo errorInfo, Message message, ITransactionContext transactionContext) { var hasPaymentException = ContainsTargetException(errorInfo.Exception, "MyProject.Exceptions.PaymentFailedException"); if (hasPaymentException) { await _slackService.SendPaymentFailureAlert(message, errorInfo); } else { await _slackService.SendGeneralFailureAlert(message, errorInfo); } } }
方案2:使用自定义中间件捕获原始异常
若希望完全复用 Rebus 7 的逻辑,可通过自定义入站消息中间件在异常被序列化为 ExceptionInfo 之前捕获原始异常:
// 注册中间件 Configure.With(container) .Transport(t => t.Use...()) .Options(options => { options.Decorate<IPipeline>(c => { var originalPipeline = c.Get<IPipeline>(); return new PipelineStepInjector(originalPipeline) .OnReceive(new SlackErrorReportingMiddleware(c.Get<ISlackNotificationService>()), PipelineRelativePosition.After, typeof(HandleMessageStep)); }); }) .Start(); // 自定义中间件类 public class SlackErrorReportingMiddleware : IIncomingStep { private readonly ISlackNotificationService _slackService; public SlackErrorReportingMiddleware(ISlackNotificationService slackService) { _slackService = slackService; } public async Task Process(IncomingStepContext context, Func<Task> next) { try { await next(); } catch (Exception ex) { // 直接操作原始Exception及InnerException,完全复用Rebus7的上报逻辑 await _slackService.SendFailureNotification(ex, context.Load<Message>().Headers); throw; // 必须重新抛出,保证Rebus的重试、死信队列等流程正常执行 } } }
该方案优势:
- 无需适配
ExceptionInfo,迁移成本极低; - 可在消息重试阶段就上报错误,覆盖更多错误场景;
- 保留原始异常的完整上下文信息。
内容的提问来源于stack exchange,提问作者xhafan
相关产品推荐
相关产品推荐

