重用重试政策

时间:2019-05-16 11:18:36

标签: rebus rebus-azureservicebus

我对以下Rebus重试政策有疑问:

Configure.With(...)
    .Options(b => b.SimpleRetryStrategy(maxDeliveryAttempts: 2))
    .(...)

https://github.com/rebus-org/Rebus/wiki/Automatic-retries-and-error-handling#customizing-retries

1它既可以用于发布者(入队消息)又可以用于订户(出队消息)吗?

2我有一个无法使消息出队的订户。因此,消息被发送到错误队列。

以下是将消息放入错误队列时的错误。但是我看不到重试日志。

[ERR] Rebus.Retry.PoisonQueues.PoisonQueueErrorHandler (Thread #9): Moving messa
ge with ID "<unknown>" to error queue "poison"
Rebus.Exceptions.RebusApplicationException: Received message with empty or absen
t 'rbs2-msg-id' header! All messages must be supplied with an ID . If no ID is p
resent, the message cannot be tracked between delivery attempts, and other stuff
 would also be much harder to do - therefore, it is a requirement that messages
be supplied with an ID.

是否可以为每次重试定义和存储自定义日志记录,而不是在IErrorHandler中?

3默认情况下,两次重试之间要等待多长时间?

4是否可以为每次重试定义自定义等待时间(不在IErrorHandler中)?如果是,此扫描方式是否支持Polly?如下所示:

Random jitterer = new Random(); 
Policy
  .Handle<HttpResponseException>() // etc
  .WaitAndRetry(5,    // exponential back-off plus some jitter
      retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))  
                    + TimeSpan.FromMilliseconds(jitterer.Next(0, 100)) 
  );

https://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/implement-resilient-applications/implement-http-call-retries-exponential-backoff-polly

更新

如何测试重试策略?

以下是我根据以下代码尝试的内容:

public class StringMessageHandler : IHandleMessages<String>
{   
    public async Task Handle(String message) 
    {
          //retry logic with Polly here
    }   
}

我向字符串主题发送了一个字符串类型的无效消息,但是,根本没有调用Handle(String message)。

1 个答案:

答案 0 :(得分:1)

Rebus的重试机制仅在接收消息时才相关。它通过创建“队列事务”(*)来工作,然后,如果消息处理失败,则消息将回滚到队列。

此后不久,该消息将再次被接收并尝试进行处理。这意味着交付尝试之间没有延迟。

对于每次失败的传递,该消息的ID的计数器都会增加。这就是为什么要使Rebus正常工作必须使用消息ID的原因,这也解释了为什么没有ID的消息会立即移至死信队列。

由于投递尝试的不连贯性(每个消息ID仅存储一个计数器),因此没有很好的位置挂接到Polly之类的重试库中。

如果您想简化消息处理,建议您使用Polly策略执行单独的操作-这样,您可以轻松地使用不同的策略来处理失败的Web请求,失败的网络驱动器上的文件传输等。我自己很多。

为避免在长时间的Polly重试过程中无法正确关闭总线实例,可以将Rebus的内部CancellationToken传递给Polly执行,如下所示:

public class PollyMessageHandler : IHandleMessages<SomeMessage>
{
    static readonly IAsyncPolicy RetryPolicy = Policy
        .Handle<Exception>()
        .WaitAndRetryForeverAsync(_ => TimeSpan.FromSeconds(10));

    readonly IMessageContext _messageContext;

    public PollyMessageHandler(IMessageContext messageContext)
    {
        _messageContext = messageContext;
    }

    public async Task Handle(SomeMessage message) 
    {
        var cancellationToken = _messageContext.GetCancellationToken();

        await RetryPolicy.ExecuteAsync(DoStuffThatCanFail, cancellationToken);
    }

    async Task DoStuffThatCanFail(CancellationToken cancellationToken)
    {
        // do your risky stuff in here
    }
}

(*)事务的实际类型取决于传输支持的内容。

对于MSMQ,它是一个MessageQueueTransaction对象,上面具有Commit()Rollback()方法。

对于RabbitMQ,Azure Service Bus和其他服务器,它是基于租约的协议,其中消息在一段时间内不可见,然后,如果在该时间内确认了该消息,则该消息将被删除。否则-如果消息已被拒绝或已被拒绝,或者租约到期,则消息会再次弹出,并可以被其他使用者再次接收。

使用SQL传输,这只是数据库事务。