How to restart the message consumer in Spring Integration? - spring

My consumer, e.g. service activator that is consuming messages coming from ActiveMQ fromChannel should be restarted when exception occurs or ActiveMQ fails. How to do it for the following spring integration context ?
<!-- RECEIVER. message driven adapter -> jmsInChannel -> activator. -->
<si:channel id="fromChannel"/>
<int-jms:message-driven-channel-adapter id="messageDrivenAdapter"
channel="fromChannel" destination="forward" connection-factory="connectionFactory"
max-concurrent-consumers="2" auto-startup="true" acknowledge="auto" extract-payload="false" />
<si:service-activator id ="activator"
input-channel="fromChannel"
ref="messageService"
method="process"/>
<bean id="messageService" class="com.ucware.ucpo.forward.jms.MessageService"/>
My first idea was to use Retry Advice and add to a service but am not sure if this a right solution for unhandled exceptions. I also would like the receiver to restart if the ActiveMQ server is down.

The listener container within the message-driven-channel-adapter will automatically keep trying to reconnect when it loses connectivity to the broker.
If you set `acknowledge="transacted"' the message will be rolled back on an exception and the broker will resubmit it.
A stateful retry advice would allow you to give up and take some other action after some number of retries (but you can also configure that into ActiveMQ itself where it will send the message to a DLQ after some number of delivery attempts).

Reading your post I instantly thought of this video. Which gives a good insight on how to monitor and control SI application through itself.
Additionally you should have a look at ApplicationEvent documentation of SI.
Glueing that all together you could monitor the JMS message adapter with JMX and stop and restart it through sending an ApplicationEvent on issues. Regarding catching exceptions it depends on what Exceptions you actually want to handle. I'd create an errorChannel that receives exceptions being thrown by components and create a new service that restarts these components after receiving errors.
Following your idea leveraging Spring Retry's capabilites in SI.

Related

Spring Integration - JMS to Kafka message transfer - End to End Transaction

I am consuming messages from JMS ActiveMQ using the following code:
<jms:message-driven-channel-adapter
id="helloJMSAdapater" destination="helloJMSQueue" connection-factory="jmsConnectionfactory"
channel="helloChannel" extract-payload="true" />
<integration:channel id="helloChannel" />
My requirement is to consume from here and post it to Kafka outbound adapter. Using the below config:
<int-kafka:outbound-channel-adapter
id="kafkaOutboundChannelAdapter"
kafka-producer-context-ref="kafkaProducerContext"
channel="inputToKafka">
</int-kafka:outbound-channel-adapter>
Here are what i want to achieve:
My queue is a durable topic and dont want to acknowledge the records unless it is successfully published to Kafka. In short, i want to have a transaction behaviour from consuming message from jms to publishing it to Kafka.
I noticed that my messages are immediately dequeued and if processing encounters some exception, i am unable to reprocess it. I dont want that to happen.
Also, when kafka encounters some issue, i want it to be returned to some method so that i can persist the failure message and as said before does not want to acknowledge it.
I am really struggling to get it to work. Can someone please help me out?
You really can have transaction-manager on the <jms:message-driven-channel-adapter> to start TX.
When <int-kafka:outbound-channel-adapter> throws an exception it causes the TX to be ralled back and therefore the message will be requeued.
If you are interested in the persisting errors, there is an error-channel option on the <jms:message-driven-channel-adapter>, but you still have to re-throw exception to let TX to rallback.
To make all that to work you should be sure that there is only single thread from the begging to the end. No <queue> or executor channel in the flow.
Also it isn't clear why do you use so old Apache Kafka still...

Why does my camel route try to reply to the JMS consumer?

I have an Apache Camel route configured in Spring which takes a message from a JMS (ActiveMQ) queue, transforms the message and uses the CXF component to send the results to a web service. This all works fine but I always get an exception thrown at the end of the route that the CXF response object isn't synchronizable, referring to the fact that it's trying to convert the exchange/message body back into a JMS message. But why?
Here's my camel context extract:-
<route>
<from uri="jms:queue:transactions" />
<process ref="convertToFormatForCXF" />
<to uri="cxf:bean:myService?defaultOperationName=process" />
<stop />
</route>
and here's a snippet from the logs:-
EndpointMessageListener WARN Execution of JMS message listener failed. Caused by: [org.apache.camel.RuntimeCamelException - java.lang.RuntimeException: net.sophis.soa.dataexchange.LogoutResponse]
org.apache.camel.RuntimeCamelException: java.lang.RuntimeException: net.sophis.soa.dataexchange.LogoutResponse
at org.apache.camel.util.ObjectHelper.wrapRuntimeCamelException(ObjectHelper.java:1363)
at org.apache.camel.component.jms.EndpointMessageListener.onMessage(EndpointMessageListener.java:124)
Even the doesn't prevent the stack trace. Now I've found out that if I add the disableReplyTo=true to the JMS consumer then the stacktrace doesn't show which is excellent.
I suppose I'm just trying to work out what was happening? Was the CXF response object going to be added to the 'transactions' JMS queue? My intention was for the flow to stop once the CXF producer had completed.
Can anyone help my understanding please? The Camel documentation wasn't much help on this.
Was the CXF response object going to be added to the 'transactions' JMS queue?
No. It would have been added to a temporary queue.
From http://camel.apache.org/jms.html#JMS-Request-replyoverJMS
The JmsProducer detects the InOut and provides a JMSReplyTo header with the reply destination to be used. By default Camel uses a temporary queue, but you can use the replyTo option on the endpoint to specify a fixed reply queue (see more below about fixed reply queue).
Camel will automatic setup a consumer which listen on the reply queue, so you should not do anything.

Redelivering Activemq messages after consumer throws exception

I have a spring application with a consumer to consume messages and write them to a database. I'm using the spring DefaultMessageListenerContainer. Is there a way to consume a message and upon a database exception being thrown put the message back onto the queue?
setSessionTransacted(true)
If you are using the namespace to configure the container, use
<jms:listener-container acknowledge="transacted" ...>
<jms:listener ... />
</jms:listener-container>
You also might want to synchronize the database and JMS transactions by adding the JDBC transaction manager to the container configuration.
See Dave Syer's Javaworld Article about Distributed transactions in Spring, with and without XA

Spring Integration <inbound-channel-adapter> Rabbit MQ getting disconnected

We are working on a POC to use Spring integration and Rabbit MQ.
We have two modules producer module and consumer module both are runs in different JVMs.
The Producer module listen on a Folder (input folder) as soon as new files arrives, creates a message then push to (incoming.q.in) queue and also move to process folder.
The Consumer module then pickups the messages from the incoming.q.in Queue then process the files them move to complete folder.
Both Producer and Consumer code is working fine but after some ideal item then consumer module is getting disconnecting from Rabbit MQ. We see messages in incoming.q.in queue but the consumer is not processing.
When I logged into Rabbit MQ Admin/Management tool “incoming.q.in” consumer list is empty and the message is “... no consumers ...”.
The consumer code
<int-amqp:inbound-channel-adapter channel="inBoundfile" queue-names="incoming.q.in" connection-factory="connectionFactory"
error-channel="error.in">
</int-amqp:inbound-channel-adapter>
<int:header-enricher input-channel="inBoundfile" output-channel="serviceInbound">
<int:header name="FILEID" expression="payload.fileID" />
</int:header-enricher>
<int:service-activator ref="routerService" method="processFile" input-channel="serviceInbound" output-channel="fileHandler.router.in" />
....
I appreciate your help.
Turn on DEBUG logging on the consumer side; you'll see lots of logging and reconnection attempts if/when a connection is lost.

How to stop exception propagation if jms broker is down when sending a message with spring integration?

I configured spring xml based interceptor, which sends a jms message to activemq queue on each invokation of some transactional method after it is commited. It's happening with the following xml code.
<jms:outbound-channel-adapter channel="filteredStakesChannel" destination="stakesQueue" delivery-persistent="true" explicit-qos-enabled="true" />
But if the activemq server is down i get connection refused exception, which is propagated and i don't want this to happen even if the jms delivery fails. Is this possible?
Should i use some error-channel?
The simplest solution is to make fileredStakesChannel an Executor channel and the send will run on a different thread.
http://static.springsource.org/spring-integration/reference/html/messaging-channels-section.html#executor-channel
http://static.springsource.org/spring-integration/reference/html/messaging-channels-section.html#channel-configuration-executorchannel
Use the <task/> namespace to define an executor to use.

Resources