Я использую служебную шину Azure с библиотекой Mass Transit в приложении .NET WebApi. У меня есть ServiceA, где я публикую свое сообщение StartProccess. Это сообщение также используется в конечном автомате — StartStateMachine.
Это сообщение отправляется в ServiceB (это функции Azure), где оно обрабатывается и отправляется. Я вынужден зарегистрировать потребителя для ServiceB в ServiceA, используя следующую запись, поскольку, судя по тому, что я нашел и прочитал, подписка должна уже существовать для функций Azure. Обычно я бы выполнил эту регистрацию с помощью MassTransit, но MassTransit не может создать потребителя без «привязки» — реализации потребителя. Это связано с тем, что потребитель находится в другом проекте/сервисе.
if (!(await adminClient.TopicExistsAsync(formatter.MessageName<StartProccess>()));
adminClient.CreateTopicAsync(formatter.MessageName<StartProccess>());
if (!(await adminClient.SubscriptionExistsAsync(formatter.MessageName<StartProccess>()), formatterCheckFunc.ConsumerFromMessageName<StartProccess>()).Value)
await adminClient.CreateSubscriptionAsync(new CreateSubscriptionOptions(formatter.MessageName<StartProccess>(), formatterCheckFunc.ConsumerFromMessageName<StartProccess>()) { MaxDeliveryCount = 1 });
Причина, по которой здесь указано максимальное количество доставок, заключается в том, что, когда потребитель выходит из строя из-за исключения, он не запускается снова десять раз. Я хочу добиться такого функционала, как общественный транспорт, который в случае ошибки немедленно вызывает реализацию IFault и не повторяет вызов.
Все работает так, как должно. Однако время от времени и очень редко, например, 1 раз из 100, я получаю сообщение StartProccess, которое попадает в DLQ с сообщением - превышено максимальное количество отправок. Я не понимаю, почему. Это действительно устанавливает его время от времени. Таким образом, моя государственная машина не запускается и работает очень неуклюже.
Кто-нибудь сталкивался с этой проблемой? Спасибо
Редактировать:
Обработка сообщений
try
{
await _receiver.HandleConsumer<Consumer>(TopicName, SubscriptionName, message, cancellationToken);
await messageActions.CompleteMessageAsync(message);
}
catch (SomeException ex)
{
await messageActions.AbandonMessageAsync(message);
_log.LogWarning("LogIt");
}
catch
{
// This?
await messageActions.CompleteMessageAsync(message);
// Or this?
await messageActions.DeadLetterMessageAsync(message);
throw;
}
Все работает так, как должно. Однако время от времени и очень редко, например, 1 раз из 100, я получаю сообщение StartProccess, которое попадает в DLQ с сообщением - превышено максимальное количество отправок.
Причиной этого является установка MaxDeliveryCount
на 1.
Значение единицы означает одну попытку обработки. Если эта единственная попытка по какой-либо причине окажется неудачной, сообщение останется мертвым.
Это не неловко — так задумано. Обработка сообщения может завершиться неудачно по разным причинам. Функция может быть прекращена, связь с брокером ASB может прерваться и т. д. Если вы установите MaxDeliveryCount
на 1, в DLQ будут время от времени появляться сообщения. Вы предполагаете, что исключение возникнет только в том случае, если в сообщении есть логическая ошибка. Но это не так.
Я понимаю. Я понимаю, что максимальное количество доставок не должно быть единицей. Однако я не могу найти решение: если в функции Azure возникает логическая ошибка, я не хочу повторять этот вызов.
Обычно желательно повторить попытку сообщения для его успешной обработки. В вашем случае чего-то не хватает, и основное внимание уделяется тому, как, а не почему. То, что вы просите, — это однократная обработка. Может быть, подробно опишите вариант использования и почему ваш код не должен разрешать повторную обработку сообщений?
Если при вызове функции Azure есть исключение, я не хочу его повторять. Я хочу повторить попытку только в том случае, если я явно укажу (список исключений), когда хочу разрешить повторную попытку. Но я полагаю, что мне придется реализовать эту логику самому. Я отредактировал вопрос и добавил образец. Создание исключения гарантирует, что будет вызвана очередь ошибок, и поэтому я узнаю об этом. Лучше переместить сообщение в dlq или пометить как завершенное?
Если вы ничего не можете сделать с сообщением, просто дайте ему завершиться или завершите самостоятельно, если вы обрабатываете сообщение вручную. Недоставленные сообщения имеют смысл, если вам нужно иметь возможность просмотреть или позже вручную повторить эти сообщения. Но поскольку вы используете MassTransit, у него есть лучший механизм — очередь ошибок. Я бы рассмотрел возможность использования этого вместо DLQ.
Я это понимаю, но дело в том, что я отправляю сообщение в служебную шину функции Azure, и если возникает исключение, вызов повторяется в зависимости от того, какое значение указано в MaxDeliveryCount, что неудобно. Так что, возможно, проблема скорее связана с настройкой функции Azure, поскольку, если в функции Azure возникает исключение, я не хочу его повторять.