2017-07-28 53 views
1

我有一個場景,我在我的一個處理程序中調用api,並且Api可以每個月減少6小時。因此,我設計了1秒重試,1分鐘重試和6小時重試的重試邏輯。這一切工作正常,但後來我發現長時間延遲重試不是一個好的選擇。請給我你的經驗嗎?Rebus與Rabbitmq的二級重試

謝謝!

回答

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(); 
+0

我能得到這個工作,而注入的消息上下文,但使用MessageContext.Current.Header。但現在我需要編寫一個採用假總線的單元測試,並驗證不同的消息在總線上。爲此我需要注入消息上下文並使用你的方法。你能告訴我如何使用autofac注入消息上下文嗎? –

+0

如果你使用的是官方的Rebus.Autofac軟件包,注入'IMessageContext'已經自動配置 - 所以你可以在你的處理程序中添加'IMessageContext messageContext'作爲ctor參數,然後它應該可以工作 – mookid8000

+0

非常感謝! –