У меня есть ситуация, когда у меня есть один брокер activemq с двумя очередями, Q1 и Q2. У меня есть два потребителя на основе ruby, использующие активный обмен сообщениями. Назовем их С1 и С2. Оба потребителя подписываются на каждую очередь. Я устанавливаю activemq.prefetchSize=1 при подписке на каждую очередь. Я также устанавливаю ack=client.
Рассмотрим следующую последовательность событий:
1) Сообщение, запускающее длительное задание, публикуется в очереди Q1. Назовите это М1.
2) M1 отправляется потребителю C1, запуская длительную операцию.
3) Два сообщения, запускающие короткие задания, публикуются в очереди Q2. Назовите их М2 и М3.
4) M2 отправляется C2, который быстро выполняет короткую работу.
5) M3 отправляется на C1, хотя C1 все еще выполняет M1. Он может выполнять отправку на C1, поскольку prefetchSize=1 задан для подписки на очередь, а не для соединения. Таким образом, тот факт, что сообщение Q1 уже было отправлено, не мешает отправить одно сообщение Q2.
Поскольку потребители ActiveMessaging являются однопоточными, конечным результатом является то, что M3 сидит и ожидает на C1 в течение длительного времени, пока C1 не закончит обработку M1. Итак, М3 долго не обрабатывается, несмотря на то, что потребитель С2 сидит без дела (поскольку быстро заканчивает с сообщением М2).
По сути, всякий раз, когда выполняется длинное задание Q1, а затем создается целая куча коротких заданий Q2, ровно одно из коротких заданий Q2 застревает на потребителе, ожидающем завершения длинного задания Q1.
Есть ли способ установить prefetchSize на уровне подключения, а не на уровне подписки? Я действительно не хочу, чтобы какие-либо сообщения отправлялись на C1, пока он обрабатывает M1. Другая альтернатива заключается в том, что я мог бы создать потребителя, предназначенного для обработки Q1, а затем выделить других потребителей для обработки Q2. Но я бы предпочел не делать этого, поскольку сообщения Q1 нечасты — преданные потребители Q1 будут сидеть без дела большую часть дня, занимая память.