Acknowledeging a spring message - spring-integration

I have a spring integration application and I am using message driven channel adapter for consuming the messages. This is the definition of the adapter -
<jms:message-driven-channel-adapter id="messageAdapter" destination="inQueue"
connection-factory="connectionFactory"
error-channel="errorChannel"
concurrent-consumers="${consumer.concurrent-consumers}"
acknowledge="transacted"
transaction-manager="transactionManager"
channel="channel"
auto-startup="true"
receive-timeout="50000"/>
So this message goes to my core channel and then goes through a series of service activators. In between if there is a error than this message is moved to errorChannel where I handle the errors and decide on what needs to be done with this message. For one scenario I want the message to not rollback to the queue, is it possible? I am using 'transacted' in my adapter definition so I am not sure how to drive this behaviour. Any help is greatly appreciated!

You don't describe what the transactionManager bean is. If it's a JmsTransactionManager, remove it and the container will just use local transactions.
Then, the transaction will only roll back if the flow on the error-channel throws an exception. If that error flow exits normally ("consuming" the error), the transaction will not roll back.
If it's some other transaction manager (e.g. JDBC) then remove it and start the JDBC transaction later in the flow (i.e. don't synchronize the JMS and JDBC transactions; again using a local JMS transaction).

Related

how to threat errors on spring cloud dataflow?

When deploying my microservice on spring cloud dataflow I get the following log:
No bean named 'errorChannel' has been explicitly defined. Therefore, a default PublishSubscribeChannel will be created
how do I direct error flows?
My guess is to create an errorChannel bean (as the message says). But I did not find any docs about it nor sample usages.
For example, I have a sink that executes an Insert on a database and want to direct it elsewhere if insert fails.
The default errorChannel bean has a LoggingHandler subscribed to it.
If you define your own errorHandler channel, it won't get the default LoggingHandler.
The error channel is automatically wired in.
Each consumer (or #StreamListener) gets a dedicated error channel binding.group.errors which is bridged to the global errorChannel.
You can add a #ServiceActivator to consume ErrorMessages from either of these channels.
Error channels are not applied on the producer side; you have to catch the exception yourself.

Should JmsTransactionManager be used when persisting from one JMS Queue to another JMS Queue

Requirement:
We need to retrieve a message from a JMS Queue(published by a different application) and persist the message in our JMS Queue. Need the entire flow to be transactional so in case a message cannot be persisted in the downstream JMS queue, message received from upstream JMS Queue should not be acknowledged.
My configuration is as below
<int-jms:message-driven-channel-adapter
id="MessageDrivenAdapter" channel=" jmsMessageChannel " destination="sourceDestination"
connectionFactory="CF1"
acknowledge="transacted"
/>
<int:channel id=" jmsMessageChannel " />
<int-jms:outbound-channel-adapter id="sendsomemsg"
channel=" jmsMessageChannel " destination=”finalDestination”
connectionFactory="CF2"
session-transacted="true" />
Do I need to use JmsTransactionManager in this scenario or should be above configuration suffice. We can handle duplicate messages so I believe we do not need an XA transaction.
You definitely need XA transaction here because you are using several separate transactional resources. Even if they both are JMS, that doesn't mean that they can share transaction.
OTOH you can try a solution like ChainedTransactionManager and chain two JmsTransactionManagers - one for each your JMS resource.
More info is in Dave Syer's article.
As long as you don't hand off to another thread (queue channel, task executor), and both components are using the same connection factory, the outbound operation will run in the same transaction as the inbound - the underlying JmsTemplatein the outbound adapter will use the same session that the listener container delivered the message on.

Spring Integration - JMS outbound adapter post-send database update

We previously used to have a Spring Integration flow (XML configuration-based) where we would do an update in a database after sending a message to a JMS queue. To achieve this, the SI flow was configured with a publish-subscribe queue channel as an input to a JMS Outbound Channel Adapter (order 0) and a Service Activator (order 1). The idea here being that after a successful JMS send, the service activator would be called thus, updating the data in the database.
We are now in the process of updating our flows to work with spring-integration:4.0.x APIs and wanted to use this opportunity to see if the described flow pattern is still a good/recommended way of doing a database update after a successful JMS send or if there is now a simpler/better way of achieving this? As a side note, our flows are now being implemented using spring-integration-java-dsl:1.0.0.M3 APIs.
Thanks in advance for any input on this,
PM.
publish-subscribe queue channel
There's no such thing as a pub-sub queue channel; by definition, it's a subscribable channel; so I assume that's what you mean.
It is one of the ways to do what you need, and perfectly fine; you can also achieve the same result with a RecipientListRouter. The dsl syntax is quite nice, especially with Java 8; see the SpringOne demo app for an example.

Jdbc based Queue Channel without poller. Possible?

I have a scenario where I would like to separate the flow into a number of transactions. I am using queue channels based on a JdbcChannelMessageStore to do so and that works excellent. Its robust and it just works. But because these Jdbc based queues (the database) are polled by the executors, I get a natural limitation on the throughput (I don't really want to configure the poller to poll every 1 millisecond). So my question is this, is there a way for the queue channel to notify the consumer of that channel that a new messages has been queued, and then trigger the "poller" to have a look in the database to see what has to be consumed?
So the simple scenario:
1. A queue channel where someone puts a message
2. A service activator that will process that message (in parallel)
<int:channel id="InputChannel">
<int:queue message-store="jdbcChannelStore"/>
</int:channel>
<task:executor id="TradeTransformerExecutor" pool-size="2-20" queue-capacity="20" rejection-policy="CALLER_RUNS"/>
<int:service-activator id="TradeConverter" input-channel="InputChannel" output-channel="TradeChannel" method="transform">
<beans:bean class="com.service.TradeConverter"/>
<int:poller task-executor="TradeTransformerExecutor" max-messages-per-poll="-1" receive-timeout="0" fixed-rate="100">
<int:transactional transaction-manager="dbTransactionManager"/>
</int:poller>
</int:service-activator>
<int:channel id="TradeChannel"></int:channel>
So how could I make this InputChannel notify the poller (or something else) to start executing the message right away and not wait for 100ms?
Also I don't want to use DirectChannels as I do want some persistence between defined flows for robustness reasons.
Cheers guys.
Jonas
There's no way to change a trigger on demand; you can have a dynamic trigger, but changes only take effect after the next poll.
Instead of using a JDBC-backed channel, consider using an outbound channel adapter to store the data and a JDBC outbound gateway (with just a query, no update).
Use a pub-sub channel and, after storing, send the message (perhaps via a bridged ExecutorChannel) to the gateway.
Alternatively, simply inject your queue channel into a service and invoke it via a <service-activator/>. You would need a pub-sub channel bridged to your queue channel, with the second subscriber being the service activator which, when it receives the message calls receive() on the channel.
Finally, consider using a JMS, or RabbitMQ backed-channel for high performance persistence instead - they are much better a queueing than a database.

Using Control bus to stop message-driven-channel-adapter that uses transactional session

My requirement is to use transactional session with message-driven-channel-adapter (JmsMessageDrivenEndpoint). I am able to setup the configuration buy using sessionTransacted = true for DefaultMessageListenerContainer.
Work flow: receive a message -> call the service activator -> service activator calls dao class
On successful commit to database a commit() is called by spring framework and on any runtime exception a rollback() is called by spring framework. Which works just fine. When a rollback happens JMS Broker sends the message back again to my application.
For a specific type of exception in dao I want to add a message header (i.e redelivery time) so that JMS Broker will not send the message again right away. How can I do it?
For another specific type of exception in dao I want to use control bus to stop the end point (message-driven-channel-adapter) and before stopping it rollback the previous transaction. How can I do it?
Any one can help me out?
There is no wonder, how to use Control Bus for start/stop endpoints:
<int:control-bus input-channel="controlChannel"/>
<int-jms:message-driven-channel-adapter id="jmsInboundEndpoint"/>
<int:transformer input-channel="stopImsInboundEndpointChannel"
outbound-channel="controlChannel"
expression="'#jmsInboundEndpoint.stop()'"/>
Or you can send to the controlChannel the same command string from any place of your code.
But it doesn't matter that the last transaction will be rollbacked. It depends on your 'unit of work' (in other words - the behaviour of your service).
However you can, at the same time when you send 'stop command', mark current transaction for rollback:
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
Another your question about 'adding some message header' is abnormal for Messaging at all.
If you change the message it will be a new one and you can't rollback message to the queue with some new info.
Of course, you can do it anyway and have new message. But you should resend it, not rollback. So, you should commit transaction anyway and send that new message somewhere (or to the same queue), but it will be new message as for Broker as well for your application. And one more time: for this case you have to commit transaction.
Not sure that it is very clear and I go right way in my asnwer, but hope it helps you a bit.
You cannot modify the message (add a header) before rollback. You could, of course, requeue it as a new message after catching the exception. Some brokers (e.g. ActiveMQ) provide a back-off retry policy after a rollback. That might be a better solution if your broker supports it.
You can use the control bus to stop the container, but you will probably have to do it asynchronously (invoke the stop on another thread, e.g. by using an ExecutorChannel on the control bus). Otherwise, depending on your environment you might have problems with the stop waiting for the container thread to exit, so you shouldn't execute the stop on the container thread itself.
Best thing to do is experiment.
Thanks Gary and Artem. The solution is working. I am using the below configuration:
<jms:message-driven-channel-adapter id="jmsMessageDrivenChannelAdapter" connection-factory="connectionFactory"
destination="destination" transaction-manager="jmsTransactionManager" channel="serviceChannel" error-channel="ultimateErrorChannel" />
<si:service-activator input-channel="ultimateErrorChannel" output-channel="controlChannel">
<bean class="play.spring.integration.TestErrorHandler">
<property name="adapterNeedToStop" value="jmsMessageDrivenChannelAdapter" />
<property name="exceptionWhenNeedToStop" value="play.spring.integration.ShutdownException" />
</bean>
</si:service-activator>
<si:channel id="controlChannel">
<si:dispatcher task-executor="controlBusExecutor" />
</si:channel>
<task:executor id='controlBusExecutor' pool-size='10' queue-capacity='50' />
<si:control-bus input-channel="controlChannel" />
Now my question is if I want to stop multiple inbound adapters how can I send a single message to control-bus for all these adapters?
I am going to study SpEL. Would appreciate if someone already know it.
Thanks

Resources