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

时间:2017-07-28 09:23:22

标签: rabbitmq rebus

我有一个场景,我在我的一个处理程序中调用api,并且Api可以每月下降6个小时。因此,我设计了一个重试逻辑,重试1秒,重试1分钟,重试6小时。这一切都运行正常,但后来发现长时间延迟重试不是一个好选择。请你告诉我你的经验吗?

谢谢!

1 个答案:

答案 0 :(得分:1)

如果我是你,我会使用Rebus的能力推迟未来的消息来实现这一功能。

您需要通过在延期邮件上附加和更新标题来手动跟踪失败的投放尝试次数。

这样的事情可以解决问题:

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 Server - 否则,您的延迟消息将在重新启动时丢失。

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

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