Настройте NServiceBus, чтобы регистрировать исключения, которые вызывают повторные попытки сообщения

Я использую NServiceBus 4.6 и Serilog. Я настроил NServiceBus для использования Serilog через:

global::NServiceBus.SetLoggingLibrary.Custom(new SeriLoggerFactory());

Сама фабрика тоже очень простая:

public class SeriLoggerFactory : ILoggerFactory
{
    public ILog GetLogger(Type type)
    {
        return new SeriLoggerAdapter(Log.ForContext(type));
    }

    public ILog GetLogger(string name)
    {
        var contextLogger = Log.ForContext("SourceContext", name);
        return new SeriLoggerAdapter(contextLogger);
    }
}

Я определенно получаю записи в журнале, связанные с NServiceBus, но одна вещь, которая отсутствует, это детали исключения, когда сообщение обрабатывается, но выдается исключение. Я могу видеть информацию об исключении в заголовках сообщений NServiceBus (либо непосредственно, просматривая сообщение в очереди ошибок, либо через Service Insight), но в сообщении, зарегистрированном NServiceBus, отсутствует наиболее релевантная информация:

Сообщение с идентификатором '0d255d19-85f9-4915-a27c-a41000da12ed' не удалось выполнить FLR и будет передано SLR для повторной попытки 1

или же

SLR не удалось решить проблему с сообщением 0d255d19-85f9-4915-a27c-a41000da12ed и будет перенаправлено в очередь ошибок в MYERRORQUEUE

Отсутствие каких-либо подробностей о корневом исключении затрудняет отладку. Требуется, чтобы разработчик открыл Service Insight или открыл инструмент для просмотра сообщения в самой очереди. Оба являются громоздкими, и оба испытывают недостаток в любой расширяемости.

Например, Serilog позволяет вам создавать классы ILogEventEnricher, которые могут регистрировать специальные сведения об исключении, о котором идет речь, - вещи, которые не регистрируются простым.ToString для исключения. Без NServiceBus, фактически регистрирующего мои исключения, у меня нет никакого способа извлечь эти детали.

Что мне здесь не хватает?

1 ответ

NServiceBus имеет класс с именем NServiceBus.Faults.ErrorsNotifications, который содержит следующие наблюдаемые:

  • MessageSentToErrorQueue
  • MessageHasFailedAFirstLevelRetryAttempt
  • MessageHasBeenSentToSecondLevelRetries

Вы можете подписаться на эти наблюдаемые при запуске конечной точки, как в следующем примере, в котором регистрируются сообщения об ошибках, отправляемые на первый уровень повторных попыток:

public class GlobalErrorHandler : IWantToRunWhenBusStartsAndStops
{
    private readonly ILogger _logger;
    private readonly BusNotifications _busNotifications;
    readonly List<IDisposable> _notificationSubscriptions = new List<IDisposable>();

    public GlobalErrorHandler(ILogger logger, BusNotifications busNotifications)
    {
        _logger = logger;
        _busNotifications = busNotifications;
    }

    public void Start()
    {
        _notificationSubscriptions.Add(_busNotifications.Errors.MessageHasFailedAFirstLevelRetryAttempt.Subscribe(LogWhenMessageSentToFirstLevelRetry));
    }

    public void Stop()
    {
        foreach (var subscription in _notificationSubscriptions)
        {
            subscription.Dispose();
        }
    }

    private void LogWhenMessageSentToFirstLevelRetry(FirstLevelRetry message)
    {
        var properties = new
        {
            MessageType = message.Headers["NServiceBus.EnclosedMessageTypes"],
            MessageId = message.Headers["NServiceBus.MessageId"],
            OriginatingMachine = message.Headers["NServiceBus.OriginatingMachine"],
            OriginatingEndpoint = message.Headers["NServiceBus.OriginatingEndpoint"],
            ExceptionType = message.Headers["NServiceBus.ExceptionInfo.ExceptionType"],
            ExceptionMessage = message.Headers["NServiceBus.ExceptionInfo.Message"],
            ExceptionSource = message.Headers["NServiceBus.ExceptionInfo.Source"],
            TimeSent = message.Headers["NServiceBus.TimeSent"]
        };

        _logger.Error("Message sent to first level retry. " + properties, message.Exception);
    }
}

Observable реализуется с помощью Reactive Extensions, поэтому вам придется установить пакет NuGet Rx-Core, чтобы это работало.

Другие вопросы по тегам