When message Listener in Spring integration is started, it is pulling messages and removing from the source queue, How to stop the delete of messages from source queue?
Make your listener transactional and rollback transaction, when the message from queue will be in your hands:
<int-jms:message-driven-channel-adapter channel="input"
connection-factory="connectionFactory"
transaction-manager="transactionManager"
destination-name="MY-QUEUE"/>
<int:publish-subscribe-channel id="input" />
<int:service-activator input-channel="input" order="1" ref="service" output-channel="output"/>
<int:outbound-channel-adapter channel="input" order="1"
expression="T(org.springframework.transaction.interceptor.TransactionAspectSupport)
.currentTransactionStatus().setRollbackOnly()"/>
But here is need to understand what are you going to do with that remained message in the queue: it becomes available for Listener on the next poll...
Related
Summary - Message loss during systematic shutdown of application.
I have a application written in spring integration and I am consuming requests from external systems using 'jms:message-driven-channel-adapter'. This is the configuration of the channel adapter -
<jms:message-driven-channel-adapter id="InboundAdapter" destination="InQueue"
connection-factory="connectionFactory"
channel="responseChannel"
error-channel="errorChannel"
acknowledge="transacted"
receive-timeout="50000"
auto-startup="true"/>
my response channel looks like this -
<int:chain id="processorChain" input-channel="responseChannel">
<int:service-activator method="doProcess" ref="inputProcessor" />
<int:router id="inputRouter" method="route">
<int:mapping value="REQUIRED" channel="builderChannel"/>
<int:mapping value="NOT_REQUIRED" channel="TerminateChannel"/>
<bean id="Router" class="xxx.xxx.Router">
</bean>
</int:router>
</int:chain>
Now when i perform 'kill -9 pid', then I see that the message is rolled back to the queue and it is all good. But when I am performing 'kill pid', than the message is lost somewhere. I have enabled teh jms logs and I can see that JMS listener is waiting for the message in transit to complete before closing the JMS consumer but still I don't the message rolling back to my queue. This is the logs snippet that I see in my logs
trace: 15.11.18 15:42:46.619 [Thread-10] DEBUG org.springframework.jms.listener.DefaultMessageListenerContainer - Waiting for shutdown of message listener invokers
trace: 15.11.18 15:42:46.619 [Thread-10] DEBUG org.springframework.jms.listener.DefaultMessageListenerContainer - Still waiting for shutdown of 1 message listener invokers (iteration 0)
After this logs, it is calling the service activators which are defined in the response channel.
Can someone please shed some light on above behavior, I was expecting that when we issue kill command than all messages which are in transit should be rolled back to the queue, instead of this, it is trying to call the activators defined with in channel and after calling last component which is router, it just finishes.
Any help on this topic will be really helpful!!
After some more debugging and banging my head with the system I found the exact scenario where it is happening. Let me put it thru to see if it makes sense. When a systematic shutdown is triggered, JMS is waiting for the messages in transit to finish before stopping the application, till this point everything is good. Currently this chain is being executed -
<int:chain input-channel="inputchain">
<int:transformer id="xxx" method="transform">
<bean class="xxx" />
</int:transformer>
<int:service-activator id="xxx" method="doProcess">
<bean class="xx">
<constructor-arg ref="xxx"/>
</bean>
</int:service-activator>
<int:service-activator id="xxx" ref="rulesProcessor" method="doProcess"/>
<int:service-activator id="xxx" ref="xxx" method="doProcess"/>
<!-- Existing Flow Continues -->
<int:router id="xxxRequiredRouter" method="xxxRequired">
<int:mapping value="Required" channel="firstChannel"/>
<int:mapping value="NotRequired" channel="secondChannel"/>
<bean id="xxxRouter" class="xxx.Router" />
</bean>
</int:router>
</int:chain>
<int:chain input-channel="secondChannel">
some logic
</int:chain>
So the thread finishes this chain and exits gracefully. It doesn't call my next chain 'secondChannel'. My transaction boundary doesn't finish on this chain 'inputchain', it finishes at the end of secondChannel. So I have not comnmitted this transction to database as transaction boundary is at the end of next chain, so this is not available in DB and application is thinking that chain execution is finished so it is complete, so it is not rolled back to teh queue as well. So in teh end I don't have this message in my database and it is not in queue.
So is this the case that only the chain which is being executed when shutdown was triggered will finish and it will not delegate processing to subsequent chains?
A SIGTERM kill will wait for the thread to complete its work.
Eventually the container will interrupt it, but that will only help if it's doing something that's interruptible.
The scenario is inbound jms adapter -> service activators (db search, business logic, inserts or updates)
<int-jms:message-driven-channel-adapter id="swiftAdapterInput" channel="mt950"
connection-factory="connectionFactory" destination-name="${integration.swift.jms.queue.from}" pub-sub-domain="false"
auto-startup="false" error-channel="errorChannel" transaction-manager="transactionManager" acknowledge="transacted" />
<int:service-activator input-channel="errorChannel" ref="errorHandler" />
<bean id="errorHandler" class="nest.integration.utils.error.ErrorHandler" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
When the exception was thrown during my servcie activators my errorHandler works fine but the exception was at the end(after commit), for example db unique constrat exception the message does not go to error-channel but rollbacked to jms queue only.
But I need my errorHander in this case also because I need to send email exception etc.
Tanks at advance
Best wishes, Tamas
I think your issue that you must rallback TX in your errorHandler, but don't commit.
That's why you get egyediségre vonatkozó megszorítás nem tel from DefaultMessageListenerContainer, because that DB error is caused on commit.
See here: Exceptions in Spring Integration: How to log but not intercept
Working with Spring-integration, I am using this code for logging (and I have configured the log4j).
<int:message-history/>
<int:logging-channel-adapter id="logger" auto-startup="true" log-full-message="true" level="INFO" logger-name="logger"/>
<int:channel id="messages" >
<int:queue />
<int:interceptors>
<int:wire-tap channel="logger" />
</int:interceptors>
</int:channel>
Here I am logging the full-message, but I would like to use the SpEL in order to log the ChannelName, and the message.
I need also to log the number of Messages in the Queue at each insertion or Poll but I didn't found how to do it and what to declare in the log4j.xml.
There is nothing to do for log4j: you just should configure specific category and level on the matter.
WireTap doesn't do anything with channel for which it is configured. It just sends a message to the provided channel. And it does it only onSend. It doesn't do anything onReceive.
To get deal with channel you have to implement your own ChannelInterceptor and do logging just there. I mean you don't need <wire-tap> and <logging-channel-adapter> anymore.
To get a number of Messages in the Queue you should configure:
<context:mbean-export />
<context:mbean-server />
After that all Integration components will be wrapped with *Metrics proxy.
For example the QueueChannel becomes QueueChannelMetrics.
And this info you can get from your new ChannelInterceptor before logging it together with the Message and channelName.
I am working on a POC which does the following
Uses a message driven channel adapter to recieve message in a transaction
Calls the Service Activator which uses a handler to insert the message recieved from the adapter to DB and also post message to outbound channel.
Now, if the DB insert of the message fails i want the JMS message returned back to the queue so that it can be re-tried later.
With my below configuration it doesnt seems to work.(i.e. even if there is a failure while inserting into the database the message is removed from the queue.
Any pointers or sample configuration would be helpful.
<integration:channel id="jmsInChannel">
<integration:queue/>
</integration:channel>
<int-jms:message-driven-channel-adapter id="jmsIn"
transaction-manager="transactionManager"
connection-factory="sConnectionFactory"
destination-name="emsQueue"
acknowledge="client" channel="jmsInChannel"
extract-payload="false"/>
<integration:service-activator input-channel="jmsInChannel"
output-channel="fileNamesChannel" ref="handler" method="process" />
<bean id="handler" class="com.irebalpoc.integration.MessageProcessor">
<property name="jobHashTable" ref="jobsMapping" />
</bean>
Set acknowledge="transacted" and, I presume the transactionManager is a JDBC (or JTA) transaction manager.
You also need to remove <queue/> from JmsInChannel so that the database transaction occurs on the same thread.
Spring will synchronize the database transaction with the JMS transaction.
However, read http://www.javaworld.com/javaworld/jw-01-2009/jw-01-spring-transactions.html for the implications.
If you can't make your service idempotent, you may need to look at an XA transaction manager.
we are using Spring Integration 2.1 for persisting messages into database sent by clients.
There is a queue which will be filled by a custom adapter. The configured service activator polls this queue and releases the message to a spring managed #Repository bean. All errors will be captured to an error channel and will be handled by a service. The configuration works so far fine.
My concern is that if the database is not available the service-activators polls all incoming message from the queue and puts them into the error channel. Is there a way to prevent the service-activator to poll the message if the database is obviously not available, for example by sending a test query ?
My configuraton:
<int:channel id="inChannel">
<int:queue />
</int:channel>
<bean id="service" class="some.service.Service" />
<int:service-activator ref="service"
method="write" input-channel="inChannel">
<int:poller fixed-rate="100" task-executor="srvTaskExecutor"
receive-timeout="90" error-channel="errChannel" />
</int:service-activator>
<task:executor id="srvTaskExecutor" pool-size="2-10"
queue-capacity="0" rejection-policy="DISCARD" />
<int:channel id="errChannel" />
<int:service-activator input-channel="errChannel"
ref="errorService" method="write"/>
Regards.
If you give the polling service-activator an "id", you can refer to that instance and call start() or stop() on it based on the DB being available or not. Most likely you'd want to set auto-startup="false" on that service-activator as well.
Additionally, you can even define a "control-bus" element and then send messages like "myActivator.start()" and "myActivator.stop()" to that control bus' input-channel.
Hope that helps,
Mark