Не вдаваясь в подробности о проблеме, которую мы пытаемся решить, мне нужно заставить NServiceBus сделать 1 из 5 вещей, но сейчас я просто пытаюсь заставить работать первую.То есть, учитывая ответ на вызов веб-API, мы хотим сделать отложенную повторную попытку, немедленную повторную попытку, сдаться, отменить или начать заново.Отсроченная повторная попытка выглядит так, как будто это лучше всего сделать с использованием пользовательского восстановления, поэтому я следовал этому: Пользовательская политика восстановления и придумал это
public static class UpdateEndpointConfiguration
{
public static void ConfigureEndpointForUpdateVocxoSurveyApi(this EndpointConfiguration configuration)
{
var recoverabilitySettings = configuration.Recoverability();
recoverabilitySettings.CustomPolicy(SetCustomPolicy);
}
private static RecoverabilityAction SetCustomPolicy(RecoverabilityConfig config, ErrorContext context)
{
var action = DefaultRecoverabilityPolicy.Invoke(config, context);
if (context.Exception is DelayedRetryException delayedRetryException)
{
return RecoverabilityAction.DelayedRetry(TimeSpan.FromSeconds(delayedRetryException.DelayRetryTimeoutSeconds));
}
return action;
}
}
Затем в качестве теста я сделал простое сообщениепоэтому мне не нужно заставлять веб-API делать глупые вещи:
public class ForceDelayRetry : ICommand
{
public int DelayInSeconds { get; set; }
}
, а затем «обрабатывать это»
public class TestRequestHandler : IHandleMessages<ForceDelayRetry>
{
private static readonly ILog Log = LogManager.GetLogger(typeof(TestRequestHandler));
public async Task Handle(ForceDelayRetry message, IMessageHandlerContext context)
{
Log.Info($"Start processing {nameof(ForceDelayRetry)}");
var handleUpdateRequestFailure = IoC.Get<HandleUpdateRequestFailure>();
await handleUpdateRequestFailure.HandleFailedRequest(new UpdateRequestFailed
{
DelayRetryTimeoutSeconds = message.DelayInSeconds,
Message = $"For testing purposes I am forcing a delayed retry of {message.DelayInSeconds} second(s)",
RecoveryAction = RecoveryAction.DelayRetry
}, context, 12345);
Log.Info($"Finished processing {nameof(ForceDelayRetry)}");
}
}
Я запускаю службу и в промежуткепримерно через 1,5 минуты два тестовых сообщения были обработаны примерно 5400 раз.Сообщение журнала выглядит примерно так (пропущенная трассировка стека для краткости)
20180601 15:28:47 :INFO [14] TestRequestHandler Start processing ForceDelayRetry
20180601 15:28:47 :WARN [22] NServiceBus.RecoverabilityExecutor Delayed Retry will reschedule message '690f317e-5be0-4511-88b9-a8f2013ac219' after a delay of 00:00:01 because of an exception:
20180601 15:28:47 :INFO [14] TestRequestHandler Start processing ForceDelayRetry
20180601 15:28:47 :WARN [14] NServiceBus.RecoverabilityExecutor Delayed Retry will reschedule message '7443e553-b558-486d-b7e9-a8f2014088d5' after a delay of 00:00:01 because of an exception:
20180601 15:28:47 :INFO [4] TestRequestHandler Start processing ForceDelayRetry
20180601 15:28:47 :WARN [14] NServiceBus.RecoverabilityExecutor Delayed Retry will reschedule message '690f317e-5be0-4511-88b9-a8f2013ac219' after a delay of 00:00:01 because of an exception:
20180601 15:28:47 :INFO [14] TestRequestHandler Start processing ForceDelayRetry
20180601 15:28:47 :WARN [14] NServiceBus.RecoverabilityExecutor Delayed Retry will reschedule message '7443e553-b558-486d-b7e9-a8f2014088d5' after a delay of 00:00:01 because of an exception:
, поэтому либо я делаю что-то не так, либо есть ошибка, но я не знаю, какая именно.Кто-нибудь может увидеть, в чем проблема?
edit
вот метод handleUpdateRequestFailure.HandleFailedRequest
public async Task HandleFailedRequest(UpdateRequestFailed failure, IMessageHandlerContext context, long messageSurveyId)
{
switch (failure.RecoveryAction)
{
case RecoveryAction.DelayRetry:
Log.InfoFormat("Recovery action is {0} because {1}. Retrying in {2} seconds", failure.RecoveryAction, failure.Message, failure.DelayRetryTimeoutSeconds);
await context.Send(_auditLogEntryCreator.Create(_logger.MessageIsBeingDelayRetried, messageSurveyId));
throw new DelayedRetryException(failure.DelayRetryTimeoutSeconds);
case RecoveryAction.EndPipelineRequest:
case RecoveryAction.RestartPipelineRequest:
case RecoveryAction.RetryImmediate:
case RecoveryAction.RouteToErrorQueue:
break;
}
}
, и, как указано в комментарии, ябудет иметь бесконечную повторную попытку для моего сообщения, которое я тоже узнал, но вот обновленная логика для него
private static RecoverabilityAction SetCustomPolicy(RecoverabilityConfig config, ErrorContext context)
{
var action = DefaultRecoverabilityPolicy.Invoke(config, context);
if (context.Exception is DelayedRetryException delayedRetryException)
{
if (config.Delayed.MaxNumberOfRetries > context.DelayedDeliveriesPerformed)
return RecoverabilityAction.DelayedRetry(TimeSpan.FromSeconds(delayedRetryException.DelayRetryTimeoutSeconds));
}
return action;
}