使用 Rabbitmq 在 Rebus 中进行二级重试

Second level retries in Rebus with Rabbitmq

我有一个场景,我在我的一个处理程序中调用 api,Api 每个月可能会停机 6 个小时。因此,我设计了1秒重试、1分钟重试和6小时重试的重试逻辑。这一切都很好,但后来我发现长时间延迟重试不是一件好事 option.Could 请告诉我你对此的经验?

谢谢!

如果我是你,我会使用 Rebus 将消息延迟到未来的能力来实现此功能。

不过,您需要通过在延迟邮件上附加和更新 headers 来手动跟踪失败的投递尝试次数。

像这样应该可以解决问题:

public class YourHandler : IHandleMessages<MakeExternalApiCall>
{
    const string DeliveryAttemptHeaderKey = "delivery-attempt";

    public YourHandler(IMessageContext context, IBus bus)
    {
        _context = context;
        _bus = bus;
    }   

    public async Task Handle(MakeExternalApiCall message)
    {
        try
        {
            await MakeCallToExternalWebApi();
        }
        catch(Exception exception)
        {
            var deliveryAttempt = GetDeliveryAttempt();

            if (deliveryAttempt > 5)
            {
                await _bus.Advanced.TransportMessage.Forward("error");
            }
            else
            {
                var delay = GetNextDelay(deliveryAttempt);
                var headers = new Dictionary<string, string> {
                    {DeliveryAttemptHeaderKey, (deliveryAttempt+1).ToString()}
                };

                await bus.Defer(delay.Value, message, headers);
            }
        }    
    }

    int GetDeliveryAttempt() => _context.Headers.TryGetValue(DeliveryAttemptHeaderKey, out var deliveryAttempt)
        ? deliveryAttempt
        : 0;

    TimeSpan GetNextDelay() => ...
}

当 运行 投入生产时,请记住配置某种持久订阅存储 – 例如SQL 服务器 – 否则,您的延迟消息将在重新启动时丢失。

你可以像这样配置它(在安装了 Rebus.SqlServer 包之后):

Configure.With(...)
    .(...)
    .Timeouts(t => t.StoreInSqlServer(...))
    .Start();