Очередь Azure — могу ли я убедиться, что сообщение будет прочитано только один раз?

Я использую очередь Azure, и несколько разных процессов читают из очереди.
Моя система построена таким образом, что каждое сообщение читается только один раз.
Это статья Microsoft утверждает, что очереди Azure имеют гарантию доставки как минимум один раз, что потенциально означает два процессы могут читать одно и то же сообщение из очереди.
Это поток StackOverflow утверждает, что если я использую GetMessage, то сообщение становится невидимым для всех других процессов на время ожидания невидимости.

Предполагая, что я использую GetMessage() и никогда не превышаю время невидимости сообщения до DeleteMessage, могу ли я предположить, что я получу каждое сообщение только один раз?


person Gilad Gat    schedule 28.11.2012    source источник
comment
Думаю, вы можете это предположить.   -  person Richard Astbury    schedule 28.11.2012
comment
Я задал следующий вопрос своему контактному лицу в Microsoft Azure: я сильно полагаюсь на очереди и хочу убедиться, что если я сначала выполню GetMessage(), а затем DeleteMessage() , ни один другой процесс не получит такое же сообщение из очереди. Согласно этой статье Microsoft, у очередей нет At-Most -Один раз гарантия. Означает ли это, что два процесса могут прочитать одно и то же сообщение очереди и обработать его? Ответ: Да, это именно то, что имеется в виду. Если вы хотите, чтобы каждое сообщение обрабатывалось ровно один раз, вам придется использовать очередь ServiceBus.   -  person Gilad Gat    schedule 28.11.2012


Ответы (2)


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

https://docs.microsoft.com/en-us/dotnet/api/azure.storage.queues.models.queuemessage.dequeuecount?view=azure-dotnet

person Shaun Xu    schedule 29.11.2012
comment
Что происходит, если процесс A проверяет DequeueCount и видит, что он равен 0. Затем процесс A теряет ЦП, а процесс B проверяет DequeueCount и также находит его равным 0. Затем ProcessB удаляет сообщение из очереди, а затем процесс A снова просыпается и также удаляет сообщение из очереди. Таким образом, они оба выполняют бизнес-логику в одном и том же сообщении очереди. Я что-то упустил здесь? - person Gilad Gat; 29.11.2012
comment
@Gilad - DequeueCount устанавливается службой, когда элемент удаляется из очереди, поэтому проблемы с потоками не применяются. Таким образом, вы можете достичь семантики не более одного раза, отбрасывая любые сообщения с DequeueCount > 0. Но я не думаю, что есть способ получить семантику ровно один раз с очередями. - person Brian Reischl; 29.11.2012
comment
Это правильно, как сказал 'breischl', DequeueCount поддерживается службой очереди. Это будет +1, как только сообщение будет исключено из очереди. Сама служба очереди достигает хотя бы одного раза, и если вы проверили DequeuCount > 0, то я думаю, что вы достигнете не более одного раза. Только одно: вам лучше переместить сообщения, которые удаляют из очереди ›0, в другое «ядовитое сообщение», а не просто удалять их, так как эти сообщения, вероятно, означают, что какая-то фоновая задача еще не завершена. - person Shaun Xu; 30.11.2012
comment
Но совместимо ли это DequeueCount с параллельными сценариями? Могут ли два потока удалить из очереди одно и то же сообщение одновременно и оба видят его как DequeueCount: 0? - person Mike Asdf; 22.06.2013
comment
Вы не можете полагаться на DequeCount. Сценарий @MikeAsdf действителен. В сценариях одновременного чтения Microsoft не дает никаких гарантий. Вам нужно использовать служебную шину - person Dave Hogan; 14.09.2016

Нет. Может произойти следующее:

  • ПолучитьСообщение()
  • Добавьте несколько записей в базу данных...
  • Создайте несколько файлов...
  • DeleteMessage() -> Непредвиденный сбой (сбой процесса, перезагрузка экземпляра, проблемы с сетевым подключением и т. д.)

В этом случае ваша логика была выполнена без вызова DeleteMessage. Это означает, что по истечении тайм-аута невидимости сообщение появится в очереди и будет обработано еще раз. Вам нужно будет убедиться, что ваш процесс idempotent:

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

Альтернативным решением может быть использование очередей служебной шины с режимом ReceiveAndDelete (см. эту страницу в разделе Как получать сообщения из очереди). Если вы получите сообщение, оно будет помечено как использованное и больше никогда не появится. Таким образом, вы можете быть уверены, что он будет доставлен не более одного раза (см. сравнение с очередями хранилища здесь). Но опять же, если что-то случится во время обработки сообщения (например, сбой сервера, ...), вы можете потерять ценную информацию.

Обновление:

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

  • ПолучитьСообщение()
  • Удалить сообщение()
  • ДобавитьЗаписейВБазу Данных()
  • Генерировать файлы ()
person Sandrino Di Mattia    schedule 28.11.2012
comment
Предполагая, что мой процесс никогда не падает, а DeleteMessage всегда вызывается в течение периода невидимости, могу ли я предположить, что ни один другой процесс не получит такое же сообщение? - person Gilad Gat; 28.11.2012
comment
Да (некоторый контент для удовлетворения минимального количества символов) - person Sandrino Di Mattia; 28.11.2012
comment
Если это так, я могу сделать: queue.GetMessage(); сразу же следует queue.DeleteMessage(); в этом случае у меня есть гарантия Не более одного раза. Если это так, то почему Microsoft заявляет об отсутствии гарантии максимум-один раз? - person Gilad Gat; 28.11.2012
comment
Да. Даже если DeleteMessage завершится ошибкой, вы не выполните никакой бизнес-логики, поэтому можно безопасно снова обработать сообщение в следующий раз. - person Sandrino Di Mattia; 28.11.2012
comment
Моя точка зрения такова: если то, что вы говорите, правда, почему Microsoft утверждает, что нет гарантии «максимум один раз»? - person Gilad Gat; 28.11.2012
comment
Вызов DeleteMessage() все еще может завершиться ошибкой. И гостевая ОС могла рухнуть до вызова DeleteMessage(). И ОС хоста может дать сбой. И оборудование может выйти из строя. Нет никакой гарантии, что DeleteMessage() будет вызван или будет успешным. Следовательно... нет гарантии доставки не более одного раза. - person David Makogon; 28.11.2012
comment
Верно, но если он вызывает DeleteMessage сразу после получения сообщения, вы можете предположить, что бизнес-логика выполняется не более одного раза. (Примечание: в исходном комментарии не использовался термин «не более одного раза») - person Sandrino Di Mattia; 28.11.2012
comment
Я спросил своего контактного лица MS Azure, и она ответила: если вы хотите, чтобы каждое сообщение обрабатывалось ровно один раз, вам придется использовать очередь ServiceBus. К сожалению, но поскольку это от Microsoft, я думаю, это официально... - person Gilad Gat; 28.11.2012
comment
Ответ от вашего контактного лица Microsoft неверен. Sandrino прав, и описанная здесь логика дает не более одного раза обработку сообщений. (Это ничего не говорит о доставке, только об обработке.) - person user94559; 29.11.2012
comment
Чтобы продолжить пример Sandrino: допустим, в моей очереди есть itemA и у меня есть два процесса. Возможно, что оба процесса выполнят GetMessage() и получат ItemA, но один из них (более медленный) завершится ошибкой при вызове DeleteMessage() и, следовательно, не выполнит бизнес-логику. Это верно? - person Gilad Gat; 29.11.2012