Does applying ExpressionEvaluatingRequestHandlerAdvice supress the error? - spring

adapter going out to a jms queue. I have some logic that needs to trigger both on successful deliver and on failover so i've hooked the adapter to the ExpressionEvaluatingRequestHandlerAdvice.
<jms:outbound-channel-adapter id="101Out"
channel="101DestinationChannel"
connection-factory="101Factory"
destination-expression="headers.DESTINATION_NAME"
destination-resolver="namingDestinationResolver"
explicit-qos-enabled="true">
<jms:request-handler-advice-chain>
<beans:bean class="org.springframework.integration.handler.advice.ExpressionEvaluatingRequestHandlerAdvice">
<beans:property name="onSuccessExpression" ref="success"/>
<beans:property name="successChannel" ref="normalOpsReplicationChannel"/>
<beans:property name="onFailureExpression" ref="failure"/>
<beans:property name="failureChannel" ref="failoverInitiationChannel" />
</beans:bean>
<beans:bean id="retryAdvice" class="org.springframework.integration.handler.advice.RequestHandlerRetryAdvice">>
<beans:property name="retryTemplate" ref="retryTemplate"/>
</beans:bean>
</jms:request-handler-advice-chain>
</jms:outbound-channel-adapter>
Now both of these methods are triggering appropriately and the replication/failover logic is executing fine. But on failure (when i stop the queue manager) once the process hooked up to the failureChannel completes, i see that the error is propagating back to the source of the call (an HTTP endpoint in this case).
The advice IS supposed to stop the error from propagating right?
<service-activator input-channel="failoverInitiationChannel"
ref="failoverInitiator" />
I have a service activator hooked up to the failureChannel which just mutates a singleton. Nothing i do here can have triggered the error. Moreover, the error coming back is definitely for the queue access so it can't be anything i did after the failoverInitiator activated.
org.springframework.jms.IllegalStateException: JMSWMQ0018: Failed to connect to queue manager 'APFDEV1' with connection mode 'Client' and host name 'localhost(1510)'.
I'm a very confused if i'm supposed to use the recoveryCallback on the RequestHandlerRetryAdvice or this one to actually stop the error. But i do need an action taken even on success so the ExpressionEvaluatingAdvice is a better fit to my scenario.
Thanks for the help in advance :-)

That is the default behavior. Please see the ExpressionEvaluatingRequestHandlerAdvice javadocs for the trapException property...
/**
* If true, any exception will be caught and null returned.
* Default false.
* #param trapException true to trap Exceptions.
*/
public void setTrapException(boolean trapException) {
this.trapException = trapException;
}
I will add a note the reference manual.

Related

How to stop a spring integration process

I have a spring integration xml file as below: I want to introduce a new mechanism to stop the running process whenever needed by the user. How do I include the mechanism below:
<integration:gateway id="inputGateway"
service-interface="com.service.integration.gateways.inputGateway"
default-request-channel="inputGatewayChannel"/>
<integration:channel id="inputGatewayChannel">
<integration:queue capacity="1000"/>
</integration:channel>
<integration:service-activator id="ServiceActivatorA" input-channel="inputGatewayChannel" ref="initiateService" method="process" output-channel="cleanUpServiceChannel" />
<integration:channel id="cleanUpServiceChannel"/>
<integration:service-activator id="ServiceActivatorB" input-channel="cleanUpServiceChannel" ref="processService" method="process" output-channel="luceneIndexReBuilderChannel" />
<integration:channel id="luceneIndexReBuilderChannel"/>
<integration:service-activator id="luceneIndexReBuilderServiceActivator" input-channel="luceneIndexReBuilderChannel" ref="cleanUpLuceneIndexBuilderService" method="process" output-channel="completeChannel"/>
<integration:channel id="completeChannel"/>
<integration:service-activator id="cleanCardPullCompleteServiceActivator" input-channel="completeChannel" ref="completeService" method="processFinalStep"/>
I am going to guess over here because your question is not clear. Please, clarify what exactly you'd like to stop.
But let's assume you start some long process with that flow and you'd like to interrupt it via some end-user hook.
So, consider to have an AtomicBoolean bean the state of which could be checked from time to time in your long process to interrup and can be changed externally by end-user. It can be done also per message where you store such an AtomicBoolean in the headers and check and change it same way as I explained before. Only the problem here that your long process should consult with such a state. Otherwise it cannot be stopped. Even we Thread.currentThread().interrupt().

Spring JMS / Integration thread routing

I have a Spring JMS-to-database microservice using Spring Integration to route incoming messages through a sequence of filter, transform, and service activator endpoints (the last persisting the filtered and transformed messages to an Oracle database). Messages have a primary key used in the database. We have a 5 concurrent consumer set up, based on MQ constraints in prod. All of this works.
Recently we found that the upstream producer can send two or more messages with the same primary key back-to-back. Since two separate threads are given the two messages, even MERGE SQL fails with a SQLIntegrityConstraintViolationException (both threads attempt the ON NOT MATCHED INSERT... portion of the MERGE with the database server).
So we thought to change the listener to guarantee that a specific thread would get a message with any given primary key, using a Hash of the key moduloed by the concurrent consumer count. We need to ACK the message once it is saved to the database, not before, so I want to preserve transaction semantics. But I have been unable to get this working with either a Router, or a LoadBalancer on the channel coming from our DefaultMessageListenerContainer. I've also looked at sub-classing DefaultMessageListenerContainer, but don't see the appropriate point to select a given thread.
Any recommendations?
Bean/channel XML setup, our classes renamed for brevity:
...
<bean id="listenerContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer"
p:connectionFactory-ref="consumerConnectionFactory"
p:concurrentConsumers="5"
p:maxConcurrentConsumers="5"
p:destinationName="IN_QUEUE"
p:idleConsumerLimit="5"
p:sessionTransacted="true"
p:errorHandler-ref="errorHandler"
p:autoStartup="true"
p:recoveryInterval="60000"
p:receiveTimeout="5000"/>
...
`<int-jms:message-driven-channel-adapter id="xxx-message-in"
container="listenerContainer"
error-channel="errorChannel"/>
<int:transformer id="unmarshaller"
method="unmarshalPayload"
input-channel="message-in" output-channel="filterIt">
<bean class="com.db.xyz.endpoint.UnmarshallerEndpoint"/>
</int:transformer>
<int:filter id="identifyIt" input-channel="filterIt"
output-channel="transformItC" method="isItOurs">
<bean class="com.db.xyz.service.endpoint.ItFilterEndpoint"/>
</int:filter>
<int:transformer id="transformIt"
input-channel="transformItC"
method="transform" output-channel="persistItC">
<bean class="com.db.xzy.service.endpoint.ItTransformEndpoint"/>
</int:transformer>
<int:service-activator id="persistIt" method="publish"
input-channel="persistItC">
<bean class="com.db.xyz.ilr.service.endpoint.PersistEndpoint"/>
</int:service-activator>
Along with error channel definitions, etc. The consumerConnectionFactory is just a class that selects a Solace JMS, MQ Series, or Active MQ factory based on properties.

Why PollSkipStrategy.skipPoll method is getting called on every message polled from queue?

I'm using inbound poller to process failed requests from backout queue. For scheduling, I'm using corn expression '0 0/2 * * * *' i.e. execute poller every two minutes. The scheduling is working fine as per corn, but PollSkipStrategy.skipPoll method is getting called for every message polled. I was under impression is, poll skip strategy will be execute once for each poll and not for each record polled. I have implementation for PollSkipStrategy.skipPoll, which returns true or false based on peoperty. I'm missing something here? Here is my configuration
<bean id="RegistrationEventPoller"
class="com.poller.RegistrationEventPoller">
<property name="RegistrationEventRetryCount" value="$env{RegistrationEventRetryCount}"/>
</bean>
<bean id="PollSkipAdvice" class="org.springframework.integration.scheduling.PollSkipAdvice">
<constructor-arg ref="PollSkipStrategy"/>
</bean>
<bean id="PollSkipStrategy"
class="com..poller.PollSkipStrategy">
<property name="RegistrationPollerOnOff" value="$env{RegistrationPollerOnOff}"/>
</bean>
The advice is an around advice on the whole flow (MessageSource.receive() and sending the message). When the poller fires it calls the flow for up to maxMessagesPerPoll so, yes, the advice is actually called for each message found within the poll, not just on the first poll. It simply provides a mechanism to stop calling the message source if some condition prevents you from handling messages.
A more sophisticated Smart Polling feature was added in 4.2 which gives you much more flexibility.

How to add/delete listener from listener container at run time

I want to know how can we add/delete some listener from listener container at run time.
I have configured listener container as below :
<rabbit:listener-container connection-factory="connectionFactory">
<rabbit:listener ref="Listener0" queues="ListenerQueue0" />
<rabbit:listener ref="Listener1" queues="ListenerQueue1" />
<rabbit:listener ref="Listener2" queues="ListenerQueue2" />
One method comes to mind is we can add/remove 'rabbit:listener' from xml at run time and refresh application context, so new config will be loaded.
Is this good way of doing ?
Please let me know other suggestions as well. Thanks in advance.
I would not use the approach you describe.
Each <rabbit:listener/> child element is actually a SimpleMessageListenerContainer, the <rabbit:listener-container/> is just syntactic sugar to provide common attributes for the "child" containers.
If your listener is a POJO (i.e. not a MessageListener), wrap it in a MessageListenerAdapter.
So, you can simply create a new SimpleMessageListenerContainer at runtime - be sure to call afterPropertiesSet() after configuring it and then start().

how to shutdown ThreadPoolTaskExecutor? Good way

I have ThreadPoolTaskExecutor. I should send too many emails (different emails). If I have error during email sending, I should write it in database.
<bean id="taskExecutor"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="5" />
<property name="maxPoolSize" value="10" />
<property name="WaitForTasksToCompleteOnShutdown" value="true" />
</bean>
I'm executing tasks. taskExecutor.execute(Runable). Everything works well!
#Override
public void run() {
try {
mailService.sendMail();
} catch (Throwable t) {
daoService.writeFaillStatus();
}
}
Everything seems ok! Async request are doing well!
I also have
white(true) {
if(executor.getActiveCount()==0){
executor.shutdown(); break;
}
Thread.sleep(3000)
}
Because of WaitForTasksToCompleteOnShutdown=true task never will be shut down automatically. In the other words, main thread never will be destroyed (Main thread is the thread where I invoke thread executor tasks - when I run code in eclipse, terminal is active always). Even after executor thread will finish their work my console looks like this:
I think this is because, main thread is waiting something - someone who tell that "everything is already done, relax, go and shut down"
So thought about this solution while(true). Could you tell me if this is good idea? Might be it is not good.
I know that this executor also have submit() method. I think I do not need here. Please correct me If I am not correct in this post.
Because you are using the Spring ThreadPoolTaskExecutor, you are in luck.
If you configure the following it will allow you specify a number of seconds to wait before forcing a shutdown.
<bean id="taskExecutor"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="5" />
<property name="maxPoolSize" value="10" />
<property name="WaitForTasksToCompleteOnShutdown" value="true" />
<property name="awaitTerminationSeconds" value="X" />
</bean>
Set the value of X to be however many seconds you want the process to wait before terminating.
From the documentation for awaitTerminationSeconds
If the "waitForTasksToCompleteOnShutdown"
flag has been set to true, it will continue to fully execute all ongoing tasks as well as all remaining tasks in the
queue, in parallel to the rest of the container shutting down.
In either case, if you specify an await-termination period using this property, this executor will wait for the given time
(max) for the termination of tasks. As a rule of thumb, specify a significantly higher timeout here if you set
"waitForTasksToCompleteOnShutdown" to true at the same time, since all remaining tasks in the queue will still get
executed - in contrast to the default shutdown behavior where it's just about waiting for currently executing tasks
that aren't reacting to thread interruption.
Basically, you are trying to forcefully do something that should be solely handled by the framework. It should be the framework that decides when to shut down the task executor, due to exceptional circumstances. I would remove all your code that is trying to shut down the task executor, and let Spring handle that shut down, when all your jobs have finished. Then Spring will properly shut down the main as well.
If you know before hand how many are "too many emails", I would suggest to take a look at CountDownLatch rather than the busy wait loop to check the task status.
In main thread set the
CountDownLatch latch = new CountDownLatch(TOO_MANY_EMAILS);
Pass this instance to runnable instance, where we call latch.countDown() after sending each mail.
In the main thread we wait for the latch to countdown: latch.await(). This will block main thread execution.
After which you could safely shutdown the thread pool knowing all the work has been completed.

Resources