Spring Integration + #Aysnc - Gateway vs ServiceActivator - java

I have a remote service that I'm calling to load pricing data for a product, when a specific event occurs. Once loaded, the product pricing is then broadcast for another consumer to process elsewhere.
The calling code doesn't care about the response - it's fire-and-forget, responding to an application event, and triggering a new workflow.
In order to keep the calling code as quick as possible, I'd like to use #Async here, but I'm having mixed results.
The basic flow is:
CallingCode -> ProductPricingGateway -> Aggregator -> BatchedFetchPricingTask
Here's the Async setup:
<task:annotation-driven executor="executor" scheduler="scheduler"/>
<task:scheduler id="scheduler" pool-size="1" />
<task:executor id="executor" keep-alive="30" pool-size="10-20" queue-capacity="500" rejection-policy="CALLER_RUNS" />
The other two components used are a #Gateway, which the intiating code calls, and a down-stream #ServiceActivator, that sits behind an aggregator. (Calls are batched into small groups).
public interface ProductPricingGateway {
#Gateway(requestChannel="product.pricing.outbound.requests")
public void broadcastPricing(ProductIdentifer productIdentifier);
}
// ...elsewhere...
#Component
public class BatchedFetchPricingTask {
#ServiceActivator(inputChannel="product.pricing.outbound.requests.batch")
public void fetchPricing(List<ProductIdentifer> identifiers)
{
// omitted
}
}
And the other relevant intergation config:
<int:gateway service-interface="ProductPricingGateway"
default-request-channel="product.pricing.outbound.requests" />
<int:channel id="product.pricing.outbound.requests" />
<int:channel id="product.pricing.outbound.requests.batch" />
I find that if I declare #Async on the #ServiceActivator method, it works fine.
However, if I declare it on the #Gateway method (which seems like a more appropriate place), the aggregator is never invoked.
Why?

I'm struggling to see how #Async would work anywhere here, because the starting point is when your code calls the ProductPricingGateway.broadcastPricing() method.
With #Async on the gw, what would the scheduler send?
Similarly, with #Async on the service, what would the scheduler pass in in identifiers?
The correct way to go async as soon as possible would be to make product.pricing.outbound.requests an ExecutorChannel...
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
...where the calling thread hands off the message to a task executor.

Related

Spring TaskExecutor Implementation

The application I am working on receives notifications from external systems, which I want to process sequentially, since I am experiencing some deadlocks.
I am using the TaskExecutor from Spring which is the equivalent of the JDK 1.5's Executor.
I've implemented it in the following way:
I've a java interface containing 1 method:
public interface AsynchronousService {
void executeAsynchronously(Runnable task);
}
and the corresponding implementation:
public class AsynchronousServiceImpl implements AsynchronousService {
private TaskExecutor taskExecutor;
#Override
public void executeAsynchronously(Runnable task) {
taskExecutor.execute(task);
}
#Required
public void setTaskExecutor(TaskExecutor taskExecutor) {
this.taskExecutor = taskExecutor;
}
}
Here is the configuration of the TaskExecutor. I am not sure about this configuration. Since, I want the notifications to execute sequentially, I set 1 for both, corePoolSize and maxPoolSize. This means that only 1 thread will be created in the threadpool and retrieves the notifications sequentially from the queue. I also set "false" for "WaitForTasksToCompleteOnShutdown" in order not to shutdown after each task is executed, but rather when the spring context is destroyed. Am I generally correct with my assumptions?
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="1"/>
<property name="maxPoolSize" value="1"/>
<property name="WaitForTasksToCompleteOnShutdown" value="false"/>
</bean>
Here I execute then the code:
asynchronousService.executeAsynchronously(new Runnable() {
#Override
public void run() {
someMethod.processNotification(notification)
}
});
What do you think of my implementation? Did I miss something?
I am not sure if/where I need to implement some error-handling?
EDIT:
Is there any possibilty to tweak the implementation of the task-executor in spring to use a custom queue? Or how difficult is it to prioritize the tasks in the queue? I looked at some implementations but most of them implement the executor-service from sratch without using Spring.
The application I am working on receives notifications from external
systems, which I want to process sequentially, since I am experiencing
some deadlocks.
If you process sequentially, you don't need thread pool anyway.
Since, I want the notifications to execute sequentially, I set 1 for
both, corePoolSize and maxPoolSize
This will create a fixed pool size of 1. There's only one thread so it will execute sequentially
I also set "false" for "WaitForTasksToCompleteOnShutdown" in order not
to shutdown after each task is executed, but rather when the spring
context is destroyed
This is wrong. This flag tells the pool to wait for task completion on shutdown (Eg. If you call pool.shutdownNow(), the pool will wait for any executing threads)
And to summarize: Don't use thread pool if you want to execute one by one serially without concurrent

why spring task scheduler not executing task simultaneously?

I have following configuration to run task--
<bean id="trendDataJob" class="com.ge.og.realtrack.scheduler.TrendDataJob"> </bean>
<task:scheduled-tasks>
<task:scheduled ref="trendDataJob" method="trendJob" cron="#{trendDataJob.configMap['corn_exp']}"></task:scheduled>
<task:scheduled ref="trendDataJob" method="metaDataTrendJob" cron="#{trendDataJob.configMap['metadata_corn_exp']}"></task:scheduled>
</task:scheduled-tasks>
cron expression for this is corn_exp=0 0/1 * * * ? to run every minute.
Here is problem as both method of trendDataJob schedule to run every minute but they are executing one after another first trendJob once its completed then its executing metaDataTrendJob i am not able to understand this behavior .
Also another problem is in case of method takes more than one minute to finish finish..its not triggering next call till current call finish and return.
By default the scheduler uses a ConcurrentTaskScheduler with a single thread. If you want another one configure it and pass it to the scheduled-tasks scheduler attribute.
The easiest way, in XML, is to use the scheduler element. (See this section in the reference guide).
<task:scheduler id="scheduler" pool-size="10"/>
Then simply register it on the other element.
<task:scheduled-tasks scheduler="scheduler"> ...
Have you used #EnableScheduling in your java code?
#EnableScheduling ensures that a background task executor is created. Without it, nothing gets scheduled.
For more, you can go through
Spring 3 #Scheduled – 4 Ways to Schedule Tasks
Spring Batch + Spring TaskScheduler example
Scheduling Tasks
Enable scheduling annotations
To enable support for #Scheduled and #Async annotations add #EnableScheduling and #EnableAsync to one of your #Configuration classes:
#Configuration
#EnableAsync
#EnableScheduling
public class AppConfig {
}
You are free to pick and choose the relevant annotations for your application. For example, if you only need support for #Scheduled, simply omit #EnableAsync. For more fine-grained control you can additionally implement the SchedulingConfigurer and/or AsyncConfigurer interfaces. See the javadocs for full details.
If you prefer XML configuration use the <task:annotation-driven> element.
<task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>
<task:executor id="myExecutor" pool-size="5"/>
<task:scheduler id="myScheduler" pool-size="10"/>
Notice with the above XML that an executor reference is provided for
handling those tasks that correspond to methods with the #Async
annotation, and the scheduler reference is provided for managing those
methods annotated with #Scheduled.
If you're using a default task scheduler in spring, i'm pretty sure it only runs on a single thread, hence why you cannot make them run in parallel.
You need to configure some kind of BatchScheduler with a pool size, to make it run in parallel.

Spring Integration - Invoking Methods in Application Code

I have a outbound-channel-adapter, where the relevant configuration is shown below.
<int:outbound-channel-adapter channel="foo-fileChannel" ref="foo-handlerTarget" method="handleFeedFile">
<int:poller fixed-delay="5000" receive-timeout="1000" max-messages-per-poll="10" />
</int:outbound-channel-adapter>
<int:channel id="foo-fileChannel">
<int:queue />
</int:channel>
<bean id="foo-handlerTarget" class="com.abc.FooFeedHandlerImpl">
<property name="fooDescriptorFile" value="${feed.foo.fooDescriptorFile}" />
<property name="fileIdRegex" ref="foo-fileRegex" />
<property name="processId" value="${feed.processId}" />
<property name="workingLocation" value="${feed.foo.workingLocation}" />
<property name="remoteLocation" value="${feed.foo.remoteLocation}" />
<property name="stalenessThreshold" value="${feed.foo.stalenessThreshold}" />
</bean>
And in FooFeedHandlerImpl...
public void handleFeedFile(File retrievedFile) {
handleFeedFile(retrievedFile, null);
}
public void handleFeedFile(File retrievedFile, String processKey) {
if (isHandlerForFileName(retrievedFile.getName())) {
processFeed(retrievedFile, processKey);
}
}
Questions:
Which handleFeedFile method gets invoked by the channel adapter?
When I invoke a method in the application code using Spring integration, how are the method parameters determined?
Thanks for any help!
Edit:
I ran my process locally (downloaded a local SFTP server - http://www.coreftp.com/server/index.html) and determined that the handleFeedFile(File file) method was invoked.
You probably want to refer to F.6 Message Mapping rules and conventions.
Multiple parameters could create a lot of ambiguity with regards to determining the appropriate mappings. The general advice is to annotate your method parameters with #Payload and/or #Header/#Headers Below are some of the examples of ambiguous conditions which result in an Exception being raised.
and:
Multiple methods:
Message Handlers with multiple methods are mapped based on the same rules that are described above, however some scenarios might still look confusing.
If you're not in a position to annotate your target methods, then you might be able to use a SpEL expression to call your intended method:
3.3.2 Configuring An Outbound Channel Adapter
Like many other Spring Integration components, the and also provide support for SpEL expression evaluation. To use SpEL, provide the expression string via the 'expression' attribute instead of providing the 'ref' and 'method' attributes that are used for method-invocation on a bean. When an Expression is evaluated, it follows the same contract as method-invocation where: the expression for an will generate a message anytime the evaluation result is a non-null value, while the expression for an must be the equivalent of a void returning method invocation.
According to the documentation on Spring integration, the POJO (bean foo-handlerTarget) in your case will get called with a Message object containing the payload. Have you executed your code? I'd expect it generates a NoSuchMethodError.
You need a
public void handleFeedFile(Message<?> message);
method.

Spring Integration Aggregator - lost messages

I want to collect some messages(lets say 10) and pass them as a list to the service activator instead of passing them one by one.
The context:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns=...>
<int:channel id="ch.http.in"/>
<int:channel id="ch.http.trans"/>
<int:channel id="ch.http.aggr"/>
<int-http:inbound-channel-adapter path="test" channel="ch.http.in"/>
<int:map-to-object-transformer input-channel="ch.http.in" output-channel="ch.http.trans" type="demo.Req"/>
<int:aggregator
input-channel="ch.http.trans"
output-channel="ch.http.aggr"
release-strategy-expression="size() == 10"
correlation-strategy-expression="headers['id']"
ref="aggr" method="add"/>
<int:service-activator ref="srv" method="httpTest" input-channel="ch.http.aggr"/>
<bean id="srv" class="demo.IntService"/>
<bean id="aggr" class="demo.HttpAggregator"/>
</beans>
The aggreagator:
public class HttpAggregator{
public List<Req> add(List<Req> reqs) {
System.out.println(reqs);
return reqs;
}
}
The service:
public class IntService {
public void httpTest(Req msg){
System.out.println(msg);
}
}
Req is just a POJO.
The problem is that the aggregator method is never called. Without the aggregtor the messages are passed to the service activator with no problem.
Using Spring Integration 3.0.2.RELEASE (Spring Boot 1.0.2.RELEASE)
Edit:
When I changed correlation-strategy-expression="headers['id']" to correlation-strategy-expression="payload.id"(the Req object has property id) it works when I pass different ids for every chunk(e.g. id=1 for the first 10; 2 for the next 10...) Looks that that's how the correlation strategy works. How can I baypass it? I just want to limit the size of the aggregated list.
Right; you have to correlate on something; using the headers['id'] will end up with lots of group of 1 item which will never meet the release strategy.
For a simple use case like yours, correlate on a literal - e.g. correlation-expression="'foo'" and set expire-groups-on-completion="true". This resets the group after the release, so a new one (with the same correlation id) can start on the next message.
If you want to release a partial group after some timeout, you will need a MessageGroupStoreReaper. Or, if you can upgrade to 4.0.x, the aggregator now has a group-timeout (or group-timeout-expression).

Best way to achieve thread functionality in Spring

I am doing the chat project in Java with Spring 3.2.
Normally in Java I can create a thread like this:
public class Listener extends Thread{
public void run(){
while(true){
}
}
}
and start the thread by start().
But in Spring 3.x is there any special classes or any special way to achieve the thread functionality?
My requirements:
I have 2 telecom domain servers. In my application I need to initialize the servers to create the protocol.
After the servers are initialized, I need to start two threads to listen the responses from the telecom domain servers.
What I have done was given below:
public class Listener extends Thread{
public void run(){
while(true){
if(ServerOne.protocol != null){
Message events = ServerOne.protocol.receive();
//Others steps to display the message in the view
}
}
}
}
Is it possible to do the java thread functionality with the quartz ?
If possible which one is better ? if no means , what is the reason ?
Hope our stack members will give the better solution.
Spring's TaskExecutor is a good way to run these threads in a managed environment. You could refer to http://static.springsource.org/spring/docs/3.0.x/reference/scheduling.html for some examples.
Java has what you need. I advise against using Thread manually. You should always use something that manages the threads for you. Please have a look at this: https://stackoverflow.com/a/1800583/2542027
You could use Spring's ThreadPoolTaskExecutor
You can define your executor as such in you configuration file
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor" destroy- method="shutdown">
<property name="corePoolSize" value="2" />
<property name="maxPoolSize" value="2" />
<property name="queueCapacity" value="10" />
</bean>
<task:annotation-driven executor="taskExecutor" />
In your Listener you could have a method that does all the work in it and annotate this method with the #Async annotation. Ofcourse, Listener should also be Spring managed.
public class Listener{
#Async
public void doSomething(){
while(true){
if(ServerOne.protocol != null){
Message events = ServerOne.protocol.receive();
//Others steps to display the message in the view
}
}
}
}
Now everytime doSomething is called, a new thread will be created if there are less than corePoolSize number of threads being run by the executor. Once corePoolSize number of threads are created, every subsequent call to doSomething will create a new thread only if there are more than corePoolSize but less than maxPoolSize running (not idle) threads and the thread queue is full. More about pool sizes can be read in the java docs
Note : While using #Async you might encounter the following exception if CGLIB library is not made available in your application.
Cannot proxy target class because CGLIB2 is not available. Add CGLIB to the class path or specify proxy interfaces.
To overcome this without having to add CGLIB dependencies, you can create an interface IListener that has doSomething() in it and then have Listener implement IListener
Since Spring 3, you can use #Schedule annotation:
#Service
public class MyTest {
...
#Scheduled(fixedDelay = 10)
public getCounter() {...}
}
with <context:component-scan base-package="ch/test/mytest"> and <task:annotation-driven/> in the context file
Please refer to this tutorial:http://spring.io/blog/2010/01/05/task-scheduling-simplifications-in-spring-3-0/

Categories