why spring task scheduler not executing task simultaneously? - java

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.

Related

How to call spring scheduler from UI

I have defined a spring scheduler and it works automatically based on the cron i gave but i would like to call the scheduler from UI so that this scheduler can be run whenever some one wants to run.
<bean id="schedulerToCall" class="validPackagename.schedulerToCallTask" />
I would like to call this spring bean in some controller manually.
how to call that ?
Thanks
for example your context config is like this:
<bean id="schedulerToCall" class="validPackagename.SchedulerToCallTask" />
<task:scheduled-tasks>
<task:scheduled ref="schedulerToCall" method="runTaskMethod" cron="0 1 0 * * MON"/>
</task:scheduled-tasks>
In SchedulerToCallTask.java:
#Component
public class SchedulerToCallTask{
In the controller class you can just:
#Resource
SchedulerToCallTask schedulerToCallTask;
In the controller function you want to call this task:
schedulerToCallTask.runTaskMethod();
If I understood your query correctly. since cron runs based on the cron parameters, you need to pass the current time in the cron parameter. Also that cron parameters should be passed dynamically when the use want to run.
eg:
<task:scheduled ref="cronService" method="runCron" cron="* 0 0 * * ?"></task:scheduled>

Spring Integration: Poller acting weird

I have a configuration to read the data from DB using jdbc:inbound-channel-adapter. The configuration:
<int-jdbc:inbound-channel-adapter query="SELECT * FROM requests WHERE processed_status = '' OR processed_status IS NULL LIMIT 5" channel="requestsJdbcChannel"
data-source="dataSource" update="UPDATE requests SET processed_status = 'INPROGRESS', date_processed = NOW() WHERE id IN (:id)" >
<int:poller fixed-rate="30000" />
</int-jdbc:inbound-channel-adapter>
<int:splitter input-channel="requestsJdbcChannel" output-channel="requestsQueueChannel"/>
<int:channel id="requestsQueueChannel">
<int:queue capacity="1000"/>
</int:channel>
<int:chain id="requestsChain" input-channel="requestsQueueChannel" output-channel="requestsApiChannel">
<int:poller max-messages-per-poll="1" fixed-rate="1000" />
.
.
</int:chain>
In the above configuration, I have defined the jdbc poller with fixed-rate of 30 seconds. When there is direct channel instead of requestsQueueChannel the select query gets only 5 rows (since I am using limiting the rows in select query) and waits for another 30 seconds for next poll.
But after I introduce requestsQueueChannel with queue and added poller inside requestsChain, the jdbc-inbound doesn't work as expected. It doesn't wait for another 30 second for next poll. Sometimes it polls the DB twice in a row(within a second) as if there are 2 threads running and gets two sets of rows from DB. However, there is no async handoff except these mentioned above.
My understanding is that even if there is requestsQueueChannel, once it executes the select query it should wait for another 30 seconds to poll the DB. Is there anything I am missing? I just want to understand the behavior of this configuration.
When using a DirectChannel the next poll isn't considered until the current one ends.
When using a QueueChannel (or task executor), the poller is free to run again.
Inbound adapters have max-messages-per-poll set to 1 by default so your config should work as expected. Can you post a DEBUG log somewhere?
The issue of Spring integration pollers activating twice, as though they are 2 threads, is the basically the same problem I came across here, with file system pollers:
How to prevent duplicate Spring Integration service activations when polling directory
Apparently this is a relatively common misconfiguration, where Spring root and servlet contexts both load the Spring Integration configuration. As a result of this, there are indeed two threads, and pollers can be seen to activate twice within their polling period. Usually within a few seconds of each other, as each will start when its context loads.
My approach to ensuring that the Spring Integration configuration was only loaded in a single context was to structure the project packages to ensure separation.
First define a web config which only picks up classes under the "web" package.
#Configuration
#ComponentScan(basePackages = { "com.myapp.web" })
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
Create separate root configuration classes to load beans such as services and repositories, which do not belong in the servlet context. One of these should load the Spring Integration configuration. i.e.:
#Configuration
#ComponentScan(basePackages = { "com.myapp.eip" })
#ImportResource(value = { "classpath:META-INF/spring/integration-context.xml" })
public class EipConfig {
}
An additional factor in the configuration that took a little while to work out, was that my servlet filters and web security config needed to be in the root context rather than the servlet context.

Spring ThreadPoolTaskExecutor shutdown with Async task

I'm excuting an Async task using spring task execution framework.
Doing so I annotated my method with the #Async annotation and added the following to my XML based application context:
<!-- async support -->
<task:annotation-driven executor="myAsyncExecutor" />
<task:executor id="myAsyncExecutor" pool-size="5-10" queue-capacity="100" />
Wondered in this case - how does the shutdown method of this executor gets invoked? I would like to make sure my app doesn't wait forever for this threadPool.
I could (instead of using the task namespace) define my executor as a bean and then set its destroy-method to "shutdown" but wondered regarding the task namespace definition style.
Any ideas?
Internally spring uses org.springframework.scheduling.concurrent.ThreadPoolTaskExecutorfor namespace of task:executor. If you look at the relevant source code (which is inherited) the shutdown on the executor is invoked at bean destroy; so no need to worry.

How can I use a custom executor for an #Async method?

I am using ThreadPoolExecutor as my custom executor with #ASync annotation.
In google, I have found that the task below needs to be configured in xml but I'm not sure how the myExecutor is mapped to my custom executor.
<task:annotation-driven executor="myExecutor" />
Even found that in bean properties, its path is not given.
How is it called then?
Four options:
Declare a single bean of type TaskExecutor
Declare a single bean with the name AsyncExecutionAspectSupport.DEFAULT_TASK_EXECUTOR_BEAN_NAME ("taskExecutor")
Implement AsyncConfigurer#getAsyncExecutor
For individual classes/methods, provide a qualifier of an executor bean in the #Async#value.
I am not sure I understand your question but your configuration snippet is correct provided that you have defined an Executor bean with myExecutor as id.
The javadoc of #EnableAsync has a good coverage of how this works. For instance, to create a ThreadPoolTaskExecutor with 5 core threads and 10 max threads:
<task:annotation-driven executor="myExecutor"/>
<task:executor id="myExecutor" pool-size="5-10"/>

How do I configure a custom trigger in Spring 3?

I need to configure a scheduling algorithm that is beyond the capabilities of Spring's in-build scheduling (basically "every 5 minutes, but only between 4:00h and 16:00h"). It seems that implementing the org.springframework.scheduling.Trigger interface is the way to go, which seems simple enough.
The part I can't figure out and that doesn't seem to be answered in the documentation is: how does this mix with the XML configuration? There doesn't seem to be any way of specifying a custom trigger bean in the elements of the task namespace (apart from the Quartz example).
How do I use a custom trigger in a Spring 3 application? Ideally using the Bean XML configuration.
Take a look at DurationTrigger I wrote a year ago.
public class DurationTrigger implements Trigger {
/**
* <p> Create a trigger with the given period, start and end time that define a time window that a task will be
* scheduled within.</p>
*/
public DurationTrigger( Date startTime, Date endTime, long period ) {...}
// ...
}
Here is how you would schedule such a task with this trigger:
Trigger trigger = new DurationTrigger( startTime, endTime, period );
ScheduledFuture task = taskScheduler.schedule( packageDeliveryTask, trigger );
Alternatively, you can use a CronTrigger / cron expression:
<!-- Fire every minute starting at 2:00 PM and ending at 2:05 PM, every day -->
<task:scheduled-tasks>
<task:scheduled ref="simpleProcessor" method="process" cron="0 0-5 14 * * ?"/>
</task:scheduled-tasks>
Check out this JIRA as well as this Spring Integration article
EDIT:
From the JIRA discussion, you can configure the DurationTrigger above, or any other custom trigger for that matter, using Spring Integration:
<inbound-channel-adapter id="yourChannelAdapter"
channel="yourChannel">
<poller trigger="durationTrigger"/>
</inbound-channel-adapter>
<beans:bean id="durationTrigger" class="org.gitpod.scheduler.trigger.DurationTrigger">
<beans:constructor-arg value="${start.time}"/>
<beans:constructor-arg value="${end.time}"/>
<beans:constructor-arg value="${period}"/>
</beans:bean>
It is quite simple to use Spring Integration in your project, even if you did not plan to. You can use as little as the above scheduling piece, or as much as relying on many other Enterprise Integration patterns that Spring Integration has available.
It seems using XML to configure any but the two standard triggers is not possible in Spring 3.0. It has been added as a new feature in the 3.1M2 release, though: https://jira.springsource.org/browse/SPR-8205
Thanks to Mark Fisher for pointing this out.

Categories