NServiceBus6 задерживается восстановление не задерживается
Не вдаваясь в подробности о проблеме, которую мы пытаемся решить, мне нужно заставить 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:
так что либо я делаю что-то не так, либо есть ошибка, но я не знаю какая. Кто-нибудь может увидеть в чем проблема?
редактировать
вот метод 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;
}
1 ответ
То есть, учитывая ответ на вызов веб-API, мы хотим иметь отложенную повторную попытку, немедленную повторную попытку, отказ от выполнения, отмену или начало заново. Отсроченная повторная попытка выглядит так, как будто это лучше всего сделать с помощью пользовательского восстановления
Я не уверен, что понимаю, чего вы пытаетесь достичь, помимо того, что NServiceBus уже предлагает? Позвольте немедленной и отсроченной повторной попытке сделать то, что лучше всего: сделать фактическую повторную попытку.
И если вы хотите больше функциональности, используйте сагу. Позвольте саге организовать процесс и иметь отдельный обработчик для фактического вызова внешней службы. Затем сага, основываясь на ответах этого обработчика, может решить, следует ли ей остановиться, продолжить, выбрать альтернативный путь и т. Д.
Если вы хотите обсудить это более подробно, я предлагаю вам связаться с нами по адресу support@particular.net, и мы можем организовать конференц-связь и показать вам, как мы это сделаем.