Тот самый basicReject - конец очереди говорите ?


#1

“Половина интернетов” не знает об этом

Вводная

Детальное расследование поведения флага requeue в методе BasicReject - раскопал как вы понимаете самый умный (то есть @EvilBeaver
Дело в том, что до версии 2.7 сервер RMQ всегда ставил сообщение в конец очереди при отказе от сообщения.
Начиная с версии 2.7 сервер старается наоборот, хранить сообщения в очереди в порядке их поступления и поддерживает этот порядок насколько это возможно.

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

Если резюмировать, то на версиях RMQ 2.7 и старше нельзя однозначно сказать - будет ли сообщение добавлено в конец или начало при отказе от сообщения с повторной постановкой в очередь.

конкретная цитата

When a message is requeued, it will be placed to its original position in its queue, if possible. If not (due to concurrent deliveries and acknowledgements from other consumers when multiple consumers share a queue), the message will be requeued to a position closer to queue head.

Messages can be returned to the queue using AMQP methods that feature a requeue parameter (basic.recover, basic.reject and basic.nack), or due to a channel closing while holding unacknowledged messages. Any of these scenarios caused messages to be requeued at the back of the queue for RabbitMQ releases earlier than 2.7.0. From RabbitMQ release 2.7.0, messages are always held in the queue in publication order, even in the presence of requeueing or channel closure.

Выводы

Надежно поставить сообщение в конец очереди можно только через явную переотправку. Например, с помощью механики dead-letters-exchange или полностью ручной переотправкой в ту же самую очередь методом BasicPublish.

Маленькие заметки на полях

  • " if possible" конечно взбесило - версию 2.7.0 делали так что поведение было ожидаемым, а потом внесли плавающее поведение.
  • @EvilBeaver крут

вот такой basicReject - который ваще не basic

P.S. Описание поведения и улучшения в подсистеме для клиентов планируются - чтобы вы не нарывались на такие странности

P.S.S. Всё таки придется учить коллег и клиентов понятию dead-leter-exchange через подсистему - нужно будет в очередном релизе сделать метод удобный русскому человеку типа

Компонента.ОбъявитьОчередь(ИмяОчереди, ИмяТочкиОбменаКосяками) 

пока мы тут креативим - вы можете повлиять на имя метода - только сегодня и только сейчас.


#2

не знаю, как насчет имени метода, но dead-letters навешивается через policy, поддержки которых в компоненте пока нет :slight_smile: и не уверен, что оно есть в самом протоколе amqp, и не придется делать прослойку в виде http-api


#3

ну ты прям захвалил, даже неловко стало.
Я эксперимент еще не проводил, но “в лоб” решение будет тоже довольно простым:

Клиент.ПолучитьСообщение(КлючПотребителя, ТелоСообщения);
Свойства = Клиент.ПолучитьСвойстваСообщения("ТочкаОбмена,КлючМаршрутизации");
ТочкаОбменаЧерезКоторуюПришло = Свойства.ТочкаОбмена;
КлючСКоторымПришло = Свойства.КлючМаршрутизации;
// где-то тут понимаем, что сообщение не нужно
// ..
// Отменяем и переотправляем
Клиент.ОтклонитьСообщение();
Клиент.ОтправитьСообщение(ТочкаОбменаЧерезКоторуюПришло, ТелоСообщения, КлючСКоторымПришло);

Как-то так, на глаз если набросать


#4

не уверен, что оно есть в самом протоколе amqp

Есть. Настраивается через свойства при создании очереди. В нашей компоненте поддерживается.


#5

чудесно.

10символов