RabbitMQ JMS integration in Camel, no best practice?

174 views
Skip to first unread message

Matyas Boronyai

unread,
Feb 8, 2023, 7:59:45 AM2/8/23
to rabbitmq-users
Hi,

I've been desperately looking for a proper solution for weeks now, but haven't been able to find anything proper.

Our use case is the following: in our existing system,  a handful of components communicate over ActiveMQ, using Camel and JMS. In the planned next version, the company-wise used stack contains RabbitMQ as the message broker, so our current task is to migrate existing applications to this new environment.

During prototyping, it occurred to us that the performance of one of our tests that puts a heavy load on the broker runs significantly slower, which obviously led us to the topic of connection factories and caching connections, sessions and producers. Measurements showed that with no caching at all and caching of connections, sessions and producers there is considerable time difference (with everything cached, the total time for the test is six times less then without caching).

Our Camel routes use implicitly the Spring JmsTemplate, which would definitely need a caching ConnectionFactory. However, there seems to be no solution out of the box. I have tried:

- integrating org.messaginghub's PooledJMS library( https://mvnrepository.com/artifact/org.messaginghub/pooled-jms ). It caches the connection, but leaks channels because of RMQSession.setMessageListener throwing an UnsupportedOperationException runtime exception which is then not properly handled by the code

- Spring's own CachingConnectionFactory, like suggested here ( https://groups.google.com/u/1/g/rabbitmq-users/c/2h6nNhqdXQs/m/xe9ln9rWAgAJ ). It properly caches sessions (and "caches" connections, as there is a single one), but won't cache producers, because of this code piece:

if (!(dest instanceof TemporaryQueue || dest instanceof TemporaryTopic)) {
return getCachedProducer(dest);
}

and RMQDestination implementing everything:

public class RMQDestination implements Queue, Topic, Destination, Referenceable, Serializable, TemporaryQueue, TemporaryTopic 

- in the suggestion above, the destination was manually created in beans.xml

<bean id="jmsDestination" class="com.rabbitmq.jms.admin.RMQDestination" >
<constructor-arg value="spring-integration" />
<constructor-arg value="false" />
<constructor-arg value="false" />
</bean>

which is an option, but it needs refactoring (not to mention how we would go about a possible connection failover), I would like to have something more transparent.

And I'm puzzled. I thought that it is a completely relevant use-case, and still, there seem to be no proper solution in sight, or at least I haven't been able to find it. I'm assuming that yes, one way would be to migrate to pure AMQP/RabbitMQ, but, nevertheless, I don't want to believe that there are no established best practices already for this use case.

Have I missed something obvious?

(In case it is of interest, I used Camel version 3.18 and the RabbitMQ JMS Client is version 2.8.0)

Thanks,
Matyas

Arnaud Cogoluègnes

unread,
Feb 8, 2023, 8:45:50 AM2/8/23
to rabbitmq-users
I understand your frustration, the accumulation of layers never helps, we're speaking about 4 different libraries (Camel, Spring, RabbitMQ JMS and AMQP client libraries) and a broker change here. The libraries and frameworks help shield application code from infrastructure, but unfortunately, the hard truth is that it may require more changes than expected, as every system is different.

Is declaring the RMQDestination explicitly an option? Again I understand it's a change, but it should not impact application code. I don't see any easy way to bypass the unfortunate branch you mentioned in CachingConnectionFactory.

Going pure AMQP is another option, it can be seen as painful now, but it removes an extra layer, which can prove handy in the long run. 

Matyas Boronyai

unread,
Feb 9, 2023, 3:38:46 AM2/9/23
to rabbitmq-users
Thanks for your reply!

It's already a great deal to me that you confirm that there's no obvious solutions I missed, so investigation is not just time wasted. It still makes me wonder, why there aren't any? Are we that much off the beaten path with our JMS migrating scenario?

Yes, declaring the destination explicitly or the move to pure AMQP is the two possible options I see now. Or maybe I could inject a custom DestinationResolver in Camel that would cache the destinations.

Regards,
Matyas

Arnaud Cogoluègnes

unread,
Feb 9, 2023, 7:52:46 AM2/9/23
to rabbitmq-users
> It's already a great deal to me that you confirm that there's no obvious solutions I missed, so investigation is not just time wasted. It still makes me wonder, why there aren't any? Are we that much off the beaten path with our JMS migrating scenario?

I can't say, there are so many scenarios: not hitting any problems for a given system (or hitting others), using AMQP and not JMS, not using an EIP framework like Camel or using another one, etc. 


> Yes, declaring the destination explicitly or the move to pure AMQP is the two possible options I see now. Or maybe I could inject a custom DestinationResolver in Camel that would cache the destinations.

This looks like reasonable solutions to me.

Good luck!
Reply all
Reply to author
Forward
0 new messages