I use Spring Integration to read messages from JMS, handle them and then persist them to the database using my own dbPersistor's persist method which has a return type void. I wrote a test case to verify the messages published to the JMS were successfully persisted in the db. My SI and JMS configuration are as follows for this test -
<int:poller fixed-delay="500" default="true"/>
<int:channel id="inputChannel">
<int:queue/>
</int:channel>
<int:channel id="errorChannel">
<int:queue/>
</int:channel>
<jms:message-driven-channel-adapter id="jmsInboudAdapter"
connection-factory="connectionFactory" destination-name="MessageQueue"
channel="inputChannel" error-channel="errorChannel" transaction-manager="dbTxManager"
acknowledge="transacted"/>
<int:chain id="handlerChain" input-channel="inputChannel">
<int:service-activator ref="jmsMessageHandler" method="handleMessage" />
<int:service-activator ref="dbPersistor" method="persist" />
</int:chain>
Then in the test I do the following -
jmsTemplate.send()
verifyMessageWasPersistedToDB
This works great when I just publish a single message to the db. But when I loop through jmsTemplate.send() to publish multiple messages, the main thread completes the operation while the SI threads are still executing and tries to verify the messages in DB and fails as some of the messages have not been persisted yet. My questions are -
How do I make the main thread to wait for the SI threads to finish and then invoke the verify method?
In case of a db exception and rollback how do I verify that the failed message is back in the original queue?
Thanks
AJ
inputChannel should not be a queue channel - the JMS transaction will commit when the message is inserted in the queue - the DB transaction won't be performed in the scope of the JMS transaction. You must use direct channels for that (remove the poller and <queue/>). See the documentation on transactions in Spring Integration.
You will have to poll the database for results; you could probably add an interceptor and some CountDownLatch but it's easier to just poll the DB until the results appear or some time expires.
Related
I just want to ask whether following SI configuration is OK from your point of view....
Let's have following publish subscribe channel with some subscribers...
<int:publish-subscribe-channel id="channelName" ignore-failures="false"/>
and feed it from two JMS message driven adapters:
<jms:message-driven-channel-adapter channel="channelName"
destination="JMSQueue1"
connection-factory="JMSQueue1CF1"
concurrent-consumers="1"
max-concurrent-consumers="10"
error-channel="errorChannel"
acknowledge="transacted"
task-executor="mySimpleTaskExecutor1"/>
<jms:message-driven-channel-adapter channel="channelName"
destination="JMSQueue2"
connection-factory="JMSQueue2CF2"
concurrent-consumers="1"
max-concurrent-consumers="10"
error-channel="errorChannel"
acknowledge="transacted"
task-executor="mySimpleTaskExecutor2"/>
If both of these JMS Inbound channel adapters are going to have same output channel ("channelName"), are they going to interfere their processing somehow?
My guess is that every message from both queues is going to be consumed in the different thread so processing of message from JMSQueue1 won't be waiting on message from JMSQueue2.
True or not true?
There are no issues with having multiple producers on the same channel; the threads won't "interfere" with each other.
It's exactly the same as having concurrency in the message-driven adapter (which you have).
I have been trying the reply timeout of Gateway in Spring Integration but it doesn't work in the configuration I've been using below:
<int:gateway id="TrailerGateway" service-interface="com.12lmdk.gateways.TrailerGateway"
default-request-channel="trailerChannel" default-reply-timeout="5000"/>
<int:channel id="trailerChannel" />
<int:service-activator input-channel="trailerChannel"
ref="trailerService" method="getTrailer"/>
I have read in a stackoverflow question that I should provide a reply channel on the gateway and output channel in the service activator and that channel should be pollable so I tried that as well
<int:gateway id="TrailerGateway" service-interface="com.12lmdk.gateways.TrailerGateway" default-reply-channel="trailerOutputChannel" default-reply-timeout="5000"/>
<int:channel id="trailerChannel" />
<int:channel id="trailerOutputChannel" >
<int:queue/>
</int:channel>
<int:service-activator input-channel="trailerChannel" output-channel="trailerOutputChannel" ref="trailerService" method="getTrailer"/>
This still won't work and the reply-timeout has no effect. (I've tested it by putting a Thread.sleep of 10 seconds in one of the method accessed by the service activator)
The gateway still waits for the reply of the service activator which is not what I am expecting.
How can I produce an exception or even a null response from the gateway due to timeout???
The timer doesn't start until the thread returns to the gateway. It is intended for use when the calling thread hands off the work to another thread, for example with a QueueChannel or ExecutorChannel. When the calling thread returns to the gateway, the timer starts.
I have a spring integration project. Which reads message from the qpid queue and starts some processing. To mu understanding once message is read it should be cleared from the queue.
But Even after the processing is complete. The message stays in queue in acquired state. Even if i clear the queue and drop new message the message is not picked up by the adapter.
Following is my configuration.
<jms:message-driven-channel-adapter destination-name="incoming.queue" channel="transform-jms-message-channel" connection-factory="qpidConnectionFactory"
concurrent-consumers="1" error-channel="errorChannel" acknowledge="transacted" />
<int:transformer input-channel="transform-jms-message-channel" id="reportRequestTransformer" ref="reportRequestMessageTransformer" method="transform"
output-channel="validate-parameters-channel"/>
Any help is appreciated.
I have a service which receives xml messages via an http inbound adapter and then transforms them into text that becomes the content of an email that gets sent out.
I now need to first insert these messages into a JMS queue and send the acknowledgement back as a 200 ok after the message is inserted into the Q and then carry-on with the rest of the processing.
<int-http:inbound-channel-adapter channel="inputChannel"
id="httpInbound"
auto-startup="true"
request-payload-type="java.lang.String"
path="/message"
supported-methods="POST"
error-channel="logger" >
<int-http:request-mapping consumes="application/xml" />
</int-http:inbound-channel-adapter>
<int:chain id="chain" input-channel="inputChannel" >
<int:service-activator ref="mailTransformerBean" method="transform" />
</int:chain>
The service-activator takes care of the processing to convert the xml into an email.
Before that I need to incorporate a JMS Queue into which the received messsages will be inserted and then the acknowledgement is sent back. This is so as to retain the messages and retry in case of a failure of the service.
I would like to set this up as a Transaction with the JMS queue as a endpoint.
How do i approach this?
If you are seeking something like a in-process persistence storage, take a look, please, into the SubscribableJmsChannel :
The channel in the above example will behave much like a normal <channel/> element from the main Spring Integration namespace. It can be referenced by both "input-channel" and "output-channel" attributes of any endpoint. The difference is that this channel is backed by a JMS Queue instance named "exampleQueue".
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