Каков правильный способ отказаться от сообщения Azure SB, чтобы он стал видимым снова в будущем таким образом, каким я могу управлять?

Итак, сценарий заключается в том, что я использую очередь SB, чтобы отключить исходящие обратные вызовы другим службам. Одна из стандартных проблем с обращением к другим службам заключается в том, что они могут быть недоступны для неконтролируемого количества времени. Предполагая, что я обнаруживаю, что цель отключена/не отвечает, каков наилучший шаблон для отказа от этого сообщения, чтобы он не появлялся сразу в очереди?

Вот некоторые подходы, о которых я либо знаю, пробовали или рассматриваю:

  • Очевидно, что если я просто использую BrokeredMessage::Abandon(), сообщение будет разблокировано и помещено обратно в очередь. Это явно нежелательно для этого сценария и того, чего я пытаюсь избежать.

  • Если я просто проигнорирую тот факт, что я столкнулся с ошибкой и никогда не вызываю Abandon, это не позволит ему немедленно появиться, но я действительно не обладаю тонким контролем над тем, как долго это будет отображаться снова и Я хотел бы реализовать разлагающуюся стратегию повтора.

  • Я подумал, может быть, я мог бы назвать BrokeredMessage::Abandon(IDictionary<string, object>) и каким-то образом обновить свойство ScheduledEnqueueTimeUTC, но я пробовал это, и, похоже, не существует способа повлиять на это свойство за пределы начальной отправки сообщения, Имеет смысл, но мысль стоит попробовать.

  • Я рассмотрел только использование BrokeredMessage::Complete() в этой ситуации и фактически просто присвоил новую копию сообщения с помощью набора свойств ScheduledEqueueTimeUTC.

Конечная пуля почти кажется слишком тяжелой, но я прихожу к выводу, что это, вероятно, правильный ответ, учитывая присущую природе очередей. Я просто подумал, что может быть более приятный способ сделать это в очередях Azure SB, которые мне не хватает.

Ответы

Ответ 1

Если вы хотите некоторое время отложить сообщение, и у вас есть место для записи SequenceNumber (который может находиться в состоянии сеанса в сеансовой очереди), вы можете его отменить(). Отложенные сообщения могут быть получены с помощью специальной перегрузки Receive, предоставляющей SequenceNumber; что также единственный способ получить их снова, кроме них, истекающих, так осторожно. Эта функция была создана для рабочих процессов и состояний машин, чтобы они могли справиться с прибытием сообщения вне заказа.

Ответ 2

В bullet # 2 выше: Не можете ли вы установить время TTL в сообщении при вызове Receive(TimeSpan) вместо стандартного Receive()? Затем вы можете просто отказаться от сообщения (без вызова Abandon()), и сообщение должно появиться в очереди, когда истечет срок действия TTL. Хотя это не дает вам тонкого контроля, чтобы сказать "Повторить через x секунд", это дает вам предсказуемость, когда сообщение снова появляется.

Примечание. С очередями на основе хранилища вы можете обновить тайм-аут невидимости, чтобы дать вам управление тонкой зернистостью для повторного появления сообщения.

Ответ 3

Чувствует себя немного взломанным, но решение, которое я придумал, -

try 
{
   ...
}
catch (Exception ex)
{
   await Task.Delay(30000);
   throw;
}

Таким образом, он будет ждать 30 секунд, прежде чем позволить ему отказаться. Это будет в конечном итоге мертвая буква после настроенного количества раз.

Я использую Azure Webjob для получения. Хотя я использую Task.Delay вместо Thread.Sleep, он, похоже, не освобождает поток для обработки другого элемента из очереди во время ожидания (по умолчанию, Webjobs обрабатывает 16 параллельно).

Ответ 4

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

Обратите внимание, что пока страница, которую я отправил вам, связана с верблюдом, и поэтому java все, что описано на этой странице, применимо .NET и azure. Вот еще один .NET, если ваш заинтересованный http://www.eaipatterns.com/

Ответ 5

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

Поток таков:

var newMessage = new BrokeredMessage();
// Copy message body and properties from original message...

var scheduleTimeUtc = DateTimeOffset.UtcNow.Add(...);
await queueClient.ScheduleMessageAsync(newMessage, scheduleTimeUtc);

await originalMessage.CompleteAsync()