We are using - org.springframework.jms.connection.CachingConnectionFactory , and consumerCache is enabled by default.
we are setting concurrency of 3-10.
The problem is whenever there is scaling down of consumer because of less load the consumer connection is not getting notified to AMQ but locally the connection is closed . But if the number of consumers gets increased because of more load then AMQ is getting notified and connection is getting refreshed and number of consumers gets reflected properly in AMQ.
we are using spring-jms version of 6.2.6.
Comment From: mukeshopentext
Hi Team, can we please get an update on this issue.
Comment From: mukeshopentext
Hi Team, can we please get an update on this issue.
Comment From: mukeshopentext
Hi Team, can we please get an update on this issue.
Comment From: jhoeller
I'm afraid I don't understand the scenario. On scaling down consumers, are you expecting some additional notification in addition to MessageConsumer.close()
? Are there consumers called through JmsTemplate
(which is what CachingConnectionFactory
is primarily for), or are you using CachingConnectionFactory
in combination with DefaultMessageListenerContainer
(which is not actually recommended since DMLC should preferably access the target ConnectionFactory
directly)?
We got a related issue for DefaultMessageListenerContainer
scaling down against ActiveMQ Artemis, potentially losing messages in a race condition on MessageConsumer.close()
(#34935). Is your scenario related to that?
Comment From: mukeshopentext
@jhoeller Thank you for the support.
Yes, we are using JmsTemplate, CachingConnectionFactory in combination with DefaultMessageListenerContainer. We have configured "concurrency=3-10" for the listener. Along with that we have a prefetchPolicy set to '5'. When there is a heavy load, the consumer count is increased and when the load is reduced, the consumers are becoming idle, and spring closes the connection. Even though the connection is closed, ActiveMQ lists that consumer and keep allocating messages. If the AMQ connection is refreshed, either manually by closing the connection in AMQ Console or spring increases the consumer count if again the heavy load occurs, the consumer count is updated properly in AMQ.
We have doubt here, why the consumer is not removed by AMQ, when spring is closing the consumer. Is it something to do with cacheConsumer is set to 'true' by default in the CachingConnectionFactory ?
Comment From: jhoeller
@mukeshopentext that's because of cacheConsumers=true
in CachingConnectionFactory
indeed: This keeps all MessageConsumer
instances in the cache, with only a logical close signalled by DMLC and no actual close happening until the underlying Connection shuts down. With prefetch policies and with the Artemis architecture in general, this is not recommendable.
You could try setCacheConsumers(false)
on your shared CachingConnectionFactory
- or simply use the target ConnectionFactory
directly in your DefaultMessageListenerContainer
setup. CachingConnectionFactory
is primarily meant for JmsTemplate
usage, whereas DefaultMessageListenerContainer
has its own internal caching of sessions and consumers (see its setCacheLevel
setting) and does not really benefit from CachingConnectionFactory
in any case.
Comment From: mukeshopentext
@jhoeller Thank you for the clarification.
We have been using this configuration for the past 10 years without issue. The current behavior has only started occurring after upgrading spring-jms from version 6.1.12 to 6.2.6. Previously, even with cached consumers, the DefaultMessageListenerContainer (DMLC) would correctly reflect consumer closure during scale-down— i.e., the consumer would be removed from the underlying JMS connection without requiring a shutdown. It appears that in the new version, closed consumers are not being removed from the cache as expected. We believe that when a consumer connection is closed, Spring should proactively evict that consumer from the cache to avoid stale connections.
Comment From: jhoeller
Unless you specified an idleReceivesPerTaskLimit
or maxMessagesPerTask
setting before, there was no DMLC-driven scaling down in 6.1.x; DMLC would just scale up to the maximum concurrency level and then stay there. As of 6.2 (#32260), there is a default idleReceivesPerTaskLimit
value of 10
applied, in order to actually scale down if consumers are idle long enough. Are you seeing the effect of that? You could try setting idleReceivesPerTaskLimit
to -1
in order to restore 6.1.x behavior.
Evicting consumers from the cache on DMLC-level close()
would defeat the purpose of the consumer cache, arguably. For dynamic scaling, I rather recommend setting setCacheConsumers(false)
, or passing the target ConnectionFactory
to your DefaultMessageListenerContainer
directly - without a CachingConnectionFactory
in-between. I wonder whether we should log a warning if a DefaultMessageListenerContainer
is set up with a CachingConnectionFactory
, actually.
Comment From: spring-projects-issues
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.
Comment From: spring-projects-issues
Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.