Rebus消息处理器catch块发布消息且不影响重试机制的解决方案问询
问题原因说明
你遇到的两个问题都是Rebus的默认事务机制和配置规则导致的:
- 错误事件被回滚:Rebus默认将单条消息处理周期内的所有总线操作绑定到同一个接收事务中,处理抛出异常触发事务回滚时,事务内未提交的发布、发送操作会被一并撤销。
- 二级重试配置报错:Rebus默认已经内置注册了
SimpleRetryStrategySettings,重复调用SimpleRetryStrategy()配置方法会触发重复注册冲突。
解决方案
方案1:使用独立发送总线实现每次处理失败都发布事件
如果要求每次处理失败(含每次重试阶段)都立刻发布错误事件,可以通过独立的仅发送总线实例发布事件,该实例的事务与当前消息处理事务完全隔离,不会被回滚:
- 预先初始化仅发送模式的独立总线:
// 全局初始化,仅执行一次,和主总线保持相同的序列化、传输配置 private readonly IBus _errorPublishBus = Configure.With(...) .ConfigureSqlServerTransportFromAppConfig() .Options(o => o.EnableSendingOnlyMode()) // 开启仅发送模式,不占用接收队列资源 .Logging(c => c.Log4Net()) .Start();
- 改造消息处理器:
public Task Handle(SomeMessage message) { try { // 原有业务处理逻辑 } catch (Exception ex) { // 用独立总线发布事件,事务独立提交,不会被后续异常触发的回滚影响 _errorPublishBus.PublishSomeMessageErrorEvent(ex).Wait(); throw; } return Task.CompletedTask; }
方案2:修复二级重试配置,在最终失败时发布事件
如果只要求所有重试都失败后发布错误事件,二级重试是更规范的方案,首先修复配置冲突问题:
将原有重试配置替换为RetryStrategy扩展方法,不要显式调用SimpleRetryStrategy():
_bus = Configure.With(...) .Options(r=>r.RetryStrategy( maxDeliveryAttempts: 5, // 自定义一级重试次数(含首次投递) secondLevelRetriesEnabled: true )) .ConfigureSqlServerTransportFromAppConfig() .Logging(c => c.Log4Net()) .Start();
之后实现IFailed<T>消息处理器即可,该处理器的事务与原消息处理事务隔离,发布的事件不会被回滚:
public class FailedMessageHandler : IHandleMessages<IFailed<SomeMessage>> { private readonly IBus _bus; public FailedMessageHandler(IBus bus) { _bus = bus; } public async Task Handle(IFailed<SomeMessage> failedMessage) { // 从failedMessage中可获取原消息、异常信息、重试次数等上下文 await _bus.PublishSomeMessageErrorEvent(failedMessage.ErrorDescription); // 可按需选择将原消息转到错误队列/手动重试/丢弃 await _bus.Advanced.TransportMessage.DeadLetter("处理最终失败", failedMessage.ErrorDescription); } }
内容的提问来源于stack exchange,提问作者Dex
相关产品推荐
相关产品推荐

