Руководство OnMessageOptions.AutoRenewTimeout
Может ли кто-нибудь предложить дополнительные рекомендации по использованию Azure Service Bus OnMessageOptions.AutoRenewTimeout
http://msdn.microsoft.com/en-us/library/microsoft.servicebus.messaging.onmessageoptions.autorenewtimeout.aspx
поскольку я не нашел много документации по этому параметру и хотел бы знать, является ли это правильным способом обновления блокировки сообщений
Мой прецедент:
1) Очередь обработки сообщений имеет продолжительность блокировки 5 минут (максимально допустимое)
2) Обработчик сообщений с помощью насоса сообщений OnMessageAsync для чтения из очереди (с помощью ReceiveMode.PeekLock) Длительная обработка может занять до 10 минут для обработки сообщения перед вызовом вручную msg.CompleteAsync
3) Я хочу, чтобы процессор сообщений автоматически возобновил его блокировку до момента, когда он ожидал завершения обработки (~ 10 минут). Если после этого периода он не был завершен, блокировка должна быть автоматически отпущена.
Спасибо
- ОБНОВЛЕНИЕ
Я никогда не получал больше рекомендаций по AutoRenewTimeout. Я закончил использование специального класса MessageLock, который автоматически обновляет блокировку сообщений на основе таймера.
См. суть -
https://gist.github.com/Soopster/dd0fbd754a65fc5edfa9
Ответы
Ответ 1
Чтобы обрабатывать длительную обработку сообщений, вы должны установить AutoRenewTimeout
== 10 минут (в вашем случае). Это означает, что блокировка будет обновляться в течение этих 10 минут каждый раз, когда истечет время LockDuration
.
Итак, если, например, ваш LockDuration
составляет 3 минуты, а AutoRenewTimeout
- 10 минут, то каждые 3 минуты блокировка автоматически возобновляется (через 3 мин, 6 мин и 9 мин), а блокировка автоматически отпускается через 12 минут поскольку сообщение было уничтожено.
Ответ 2
У меня такая же проблема с моими работниками. Даже сообщение успешно обрабатывалось из-за длительного времени обработки, служебная шина удаляет блокировку, применяемую к ней, и сообщение становится доступным для получения снова. Другой доступный работник принимает это сообщение и начинает его снова обрабатывать. Пожалуйста, исправьте меня, если я ошибаюсь, но в вашем случае OnMessageAsync будет вызываться много раз с тем же сообщением, и вам будет предоставлено несколько задач, одновременно обрабатывающих его. В конце процесса будет вызвано исключение MessageLockLost, потому что сообщение не имеет блокировки.
Я решил это с помощью следующего кода.
_requestQueueClient.OnMessage(
requestMessage =>
{
RenewMessageLock(requestMessage);
var messageLockTimer = new System.Timers.Timer(TimeSpan.FromSeconds(290));
messageLockTimer.Elapsed += (source, e) =>
{
RenewMessageLock(requestMessage);
};
messageLockTimer.AutoReset = false; // by deffault is true
messageLockTimer.Start();
/* ----- handle requestMessage ----- */
requestMessage.Complete();
messageLockTimer.Stop();
}
private void RenewMessageLock(BrokeredMessage requestMessage)
{
try
{
requestMessage.RenewLock();
}
catch (Exception exception)
{
}
}
С момента вашего сообщения есть несколько монтировок, и, возможно, вы решили это, поэтому вы можете поделиться своим решением.
Ответ 3
По моим личным предпочтениям OnMessageOptions.AutoRenewTimeout является слишком грубым вариантом продления аренды. Если установить его на 10 минут, и по какой-либо причине Сообщение будет .Complete() только через 10 минут и 5 секунд, сообщение снова появится в очереди сообщений, будет использовано следующим резервным рабочим и всем обработка будет выполнена снова. Это расточительно и также не дает работникам выполнять другие необработанные запросы.
Чтобы обойти это:
-
Измените рабочий процесс, чтобы убедиться, что элемент, который он только что получил из очереди сообщений, еще не был обработан. Посмотрите на результат успеха/неудачи, который хранится где-то. Если процесс уже выполнен, вызовите BrokeredMessage.Complete() и переходите к ожиданию появления следующего элемента.
-
Периодически вызывайте BrokeredMessage.RenewLock() - ДО истечения срока блокировки, как каждые 10 секунд, - и установите для OnMessageOptions.AutoRenewTimeout значение TimeSpan.Zero. Таким образом, если рабочий, который обрабатывает элемент, аварийно завершает работу, сообщение вернется в MessageQueue раньше и будет получен следующим резервным рабочим.