Is there a way to specify the time to wait for the message to be resent?

Is it possible to specify the time to wait for message resubmission for a specific exception?

eg. If the object is in the SomethingInProgress state, it throws a SomethignInProgressException and I want the message to repeat after 40m. Or is it more appropriate to raise SomethingInProgressEvent and use bus.defer?

+3


source to share


2 answers


This is part of the reason Rebus has no concept of second level retries - I just haven't seen anything that this feature can be created in a way that is generic and still flexible enough.

To answer your question shortly: No, there is no (built-in) way to change the time between attempts for a specific exception. In fact, there is no way to tweak the timeout between retries at all - the failure messages will repeat as quickly as possible and then move to the error queue if they fail to avoid "clogging the pipes".

In your case, I suggest you do something like this:



public void Handle(MyMessage message) {
    var headers = MessageContext.GetCurrent().Headers;
    var deliveryAttempt = headers.ContainsKey("attempt_no") 
        ? Convert.ToInt(headers["attempt_no"]) 
        : 0;

    try {
        DoWhateverWithThe(message);
    } catch(OneKindOfException e) {
        if (deliveryAttempt > 5) {
            bus.Advanced.Routing.ForwardCurrentMessage("error");
            return;
        }

        bus.AttachHeader(message, "attempt_no", deliveryAttempt + 1);
        bus.Defer(TimeSpan.FromSeconds(20), message);
    } catch(AnotherKindOfException e) {
        if (deliveryAttempt > 5) {
            bus.Advanced.Routing.ForwardCurrentMessage("error");
            return;
        }

        bus.AttachHeader(message, "attempt_no", deliveryAttempt + 1);
        bus.Defer(TimeSpan.FromMinutes(2), message);
    }
}

      

which I just ripped off my head, not being 100% sure that it actually compiles ... but the bottom line is we keep track of how many delivery attempts we made in the custom post header, bus.Defer

name the post the appropriate time slot for each failed attempt delivery by immediately forwarding the message to the error queue when the maximum number of delivery attempts has been exceeded.

Hope this makes sense :)

+5


source


A more recent example of how to do this:



public async Task Handle(IFailed<MyMessage> message)
{
    var maxAttempts = 10;
    var optionalHeaders = new Dictionary<string, string>();
    if (message.Headers != null && message.Headers.ContainsKey("attemptNumber"))
    {
        // increment the attempt number
        var attemptNumber = int.Parse(message.Headers["attemptNumber"]);
        attemptNumber++;
        optionalHeaders.Add("attemptNumber", attemptNumber.ToString());
        if (attemptNumber > maxAttempts)
        {
            // log I give up message, message will move to dead queue
            return;
        }
    }
    else
        optionalHeaders.Add("attemptNumber", "1");

    // if message failed to process, defer processing for 5 minutes and try again
    await Bus.Defer(TimeSpan.FromMinutes(5), message.Message, optionalHeaders);
}

      

0


source







All Articles