I have a scenario where I am reading data from database for a scheduled interval (for every 5 mins) and then execute them before the next run is started.
Below is the piece of code which does that. ThreadPoolTaskScheduler is injected as a bean from Spring.
How can I ensure all workflowSchedules executions are complete before I add the next set of records to the ThreadPoolTaskScheduler. The method queueAndExecuteWorkflowRuns gets called after every database read.
private void queueAndExecuteWorklowRuns(Seq<WorkflowSchedule> workflowSchedules) {
for (WorkflowSchedule workflowSchedule : workflowSchedules) {
try {
long minutes = ChronoUnit.MINUTES.between(OffsetDateTime.now(), workflowSchedule.getNextRunDate());
threadPoolTaskScheduler.scheduleWithFixedDelay(new Runnable() {
#Override
public void run() {
startPendingWorkflow(workflowSchedule);
}
},
TimeUnit.MINUTES.toMillis(minutes + 1));
} catch (Exception e) {
log.error("Exception while adding workflow to scheduled pool with id " + workflowSchedule.getId()
+ " and run date " +
workflowSchedule.getNextRunDate());
}
}
}
#Bean(name = "workflowSchedulerExecutor")
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
ThreadPoolTaskScheduler threadPoolTaskScheduler
= new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(1);
return threadPoolTaskScheduler;
}
Related
I have a spring boot java service I have to schedule to run on a particular time. I have enabled the #Enablescheduling and #Scheduled annotation and given the cron expression.
It's working fine. The scheduler is running at the expected time. But my concern is I should control the cron expression somewhere from outside my jar file. I have tried using it in property file but when packaging my property file also getting included in that.
Sample code:
#PostMapping(path = "getoktatodynamodb")
#Scheduled(cron = "0 0/5 0 * * ?")
#ApiOperation("Sync data to DynamoDB")
public FinalResponse getdatatodynamodb() {
FinalResponse finalResponse = new FinalResponse();
try {
LOGGER.info("Sync data to DynamoDB starts - " + new Date());
finalResponse = dynamodbuserService.dynamoDbSync();
} catch (MyRestTemplateException ex) {
LOGGER.error(ex.getMessage());
finalResponse.setResponseMessage(ex.getMessage());
finalResponse.setStatusCode(ex.getStatusCode().value());
} catch (Exception execption) {
LOGGER.error(execption.getMessage());
finalResponse.setResponseMessage(execption.getMessage());
finalResponse.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
} finally {
LOGGER.info("Sync data DynamoDB Ends - " + new Date());
}
return finalResponse;
}
The main intention is scheduler should be in our control whenever we need to change the time it should be configurable. No code change and restarting the scheduler for minor changes.
How should we achieve this also we would like to schedule this in linux ec2 instance? in case if we have better suggestion to achieve this kindly share it.
You can implement SchedulingConfigurer:
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/annotation/SchedulingConfigurer.html
This DZone article shows a really good example: https://dzone.com/articles/schedulers-in-java-and-spring which I'm showing here in case the article doesn't stay permanent.
#Configuration
#EnableScheduling
public class ScheduledConfiguration implements SchedulingConfigurer {
TaskScheduler taskScheduler;
private ScheduledFuture<?> job1;
private ScheduledFuture<?> job2;
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
ThreadPoolTaskScheduler threadPoolTaskScheduler =new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(10);// Set the pool of threads
threadPoolTaskScheduler.setThreadNamePrefix("scheduler-thread");
threadPoolTaskScheduler.initialize();
job1(threadPoolTaskScheduler);// Assign the job1 to the scheduler
// Assign the job1 to the scheduler
this.taskScheduler=threadPoolTaskScheduler;// this will be used in later part of the article during refreshing the cron expression dynamically
taskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
}
private void job1(TaskScheduler scheduler) {
job1 = scheduler.schedule(new Runnable() {
#Override
public void run() {
System.out.println(Thread.currentThread().getName() + " The Task1 executed at " + new Date());
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}, new Trigger() {
#Override
public Date nextExecutionTime(TriggerContext triggerContext) {
String cronExp = "0/5 * * * * ?";// Can be pulled from a db .
return new CronTrigger(cronExp).nextExecutionTime(triggerContext);
}
});
}
private void job2(TaskScheduler scheduler){
job2=scheduler.schedule(new Runnable(){
#Override
public void run() {
System.out.println(Thread.currentThread().getName()+" The Task2 executed at "+ new Date());
}
}, new Trigger(){
#Override
public Date nextExecutionTime(TriggerContext triggerContext) {
String cronExp="0/1 * * * * ?";//Can be pulled from a db . This will run every minute
return new CronTrigger(cronExp).nextExecutionTime(triggerContext);
}
});
}
}
I have a scheduled task which needs to launch multiple threads of the same process when executed, is it possible to set a specific number of threads to be launched when the process is kicked off?
In the application class I have the following TaskExecutor beans configured
#Bean("threadFooExecutor")
public TaskExecutor getFooExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(20);
executor.setMaxPoolSize(1000);
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setThreadNamePrefix("Foo-");
return executor;
}```
#Bean("threadBarExecutor")
public TaskExecutor getBarExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(20);
executor.setMaxPoolSize(1000);
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setThreadNamePrefix("Bar-");
return executor;
}
Async processes configured in process class
#Async("threadFooExecutor")
#Scheduled(fixedRate = 3000, initialDelay = 5000)
public void print() {
System.out.println(Thread.currentThread().getName() + " " + 1);
System.out.println(Thread.currentThread().getName() + " " + 2);
System.out.println(Thread.currentThread().getName() + " " + 3);
System.out.println(Thread.currentThread().getName() + " " + 4);
}
#Async("threadBarExecutor")
#Scheduled(fixedRate = 3000, initialDelay = 5000)
public void print2() {
System.out.println(Thread.currentThread().getName() + " " + 1);
System.out.println(Thread.currentThread().getName() + " " + 2);
System.out.println(Thread.currentThread().getName() + " " + 3);
System.out.println(Thread.currentThread().getName() + " " + 4);
}
What I would like to see is 2 or 3 of each of these threads running at the same time, but I only see each thread being run once every 3 seconds
I think that you mix things : TaskExecutor/Executor configuration and the frequency rate of the tasks executed by the scheduler.
This configuration means that the task will be executed every 3 seconds :
#Scheduled(fixedRate = 3000, ...)
Adding that : #Async("threadBarExecutor") just means that the Scheduler will use a specific Executor to run the tasks.
It doesn't mean that it will be executed as much as the thread pool size is not full in the configured Executor.
So yes it looks normal that these two tasks be triggered every 3 seconds.
If you want to run these tasks a specific number of times in parallel and every 3 seconds, #Scheduled is not enough.
You should make the scheduler method to invoke another #Asynch method. This can be defined in the same bean or in another, you don't matter.
#Async("threadFooExecutor")
#Scheduled(fixedRate = 3000, initialDelay = 5000)
public void printRepeat3Times() {
for (int i=0; i<3; i++){
print();
}
}
#Async("threadFooExecutor")
public void print() {
// ...
}
Note that as these methods are annotated with #Asynch, print() invocations don't "block" the current thread and so these could be executed in parallel thanks to the ExecutorService under the hoods.
Update: ok so based on your comments you need the following:
public class ServiceOne {
#Async
public void bgTask() {
System.out.println(Thread.currentThread().getName());
}
}
public class ServiceTwo {
#Autowired
ServiceOne serviceOne;
#Scheduled(fixedRate = 3000, initialDelay = 5000)
public void scheduledRunner() {
int i = 3;
while (i-- >0 ) {
serviceOne.bgTask();
}
}
}
This way the scheduled method will be executed every three seconds and it will spawn three parallel background tasks. The inject thingie is for the AOP to work with the default weaver which would ignore one of the annotations if methods are in the same class.
According to docs this is what's probably happening:
By default, will be searching for an associated scheduler definition: either a unique TaskScheduler bean in the context, or a TaskScheduler bean named "taskScheduler" otherwise; the same lookup will also be performed for a ScheduledExecutorService bean. If neither of the two is resolvable, a local single-threaded default scheduler will be created and used within the registrar.
I think configuring a ScheduledTaskRegistrar might help:
public class SchedulerConfig implements SchedulingConfigurer {
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(4); // Number of simultaneously running #Scheduled functions
taskScheduler.initialize();
taskRegistrar.setTaskScheduler(taskScheduler);
}
Every 5 minutes, 2 tasks run, one that updates, one that calculates.
The one that updates should always run first, but doesn't have to know anything about the calculator and visa versa.
Is there any way to manage this in a clean way without calling the other task from within.
After advice, this is my solution.
#PostConstruct
public void scheduleRunnableWithTrigger() {
logger.info("init scheduler");
scheduleTasks.schedule(() -> {
if(init.getIsInitialzed()) {
databaseUpdater.updatePrices();
for (ITechnicalAnalysis technicalAnalysis: adviser.getITechnicalAnalysis()) {
try {
CandleStick lastAddedCandleStickByCurrencyPair = candleStickService.getLatestByCurrencyPair(technicalAnalysis.getCurrencyPair());
technicalAnalysis.updateAlgorithms(lastAddedCandleStickByCurrencyPair);
logger.info(technicalAnalysis.getCurrencyPair() + " has candlesticks");
}catch (NullPointerException e) {
logger.warn(technicalAnalysis.getCurrencyPair() + " has no candlesticks");
}
}
adviser.calculateAnalyses();
}
}, periodicTrigger);
}
#Bean
public PeriodicTrigger periodicTrigger() {
PeriodicTrigger periodicTrigger = new PeriodicTrigger(TIME_TO_WAIT_FOR_DATABASE_TO_FILL, TimeUnit.MINUTES);
periodicTrigger.setInitialDelay(1);
return periodicTrigger;
}
According to the documentation. Be default there will be only one thread for scheduler.
So what you can do is you can schedule the tasks one after the other may be a second apart. This way second task will always run after first task.
Even if first task is not completed and schedule time for second task has reached, second task will have to wait for the thread from first task to be released.
You can also explicitly set the thread count for the scheduler with a bean declaration like this
#Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(THREAD_COUNT);// use 1 for this use case
return threadPoolTaskScheduler;
}
I do create a timer which start when i deploy my application, what i note is this timer not stop when i Undeploy my application?
How can this happen, and show me the result in Output netbeans?
Should i restart my server every time that i Undeploy my
application?
Singleton
#Singleton
#Startup
public class StartWhenDeploy {
private static final int PERIOD = 3000;
#PostConstruct
public void init() {
System.out.println("I will set information to start my task");
Timer timer = new Timer();
timer.schedule(new TimerAction(1), new Date(), PERIOD);
}
}
TimerTask
public class TimerAction extends TimerTask {
public int nbrUsers;
public TimerAction(int nbrUsers) {
this.nbrUsers = nbrUsers;
}
#Override
public void run() {
System.out.println("This task is planified to execute at " + new Date());
System.out.println("Creation " + (createUser() ? "------------Success------------" : "------------Failed------------"));
}
public boolean createUser() {
try {
System.out.println("-------------->" + nbrUsers);
for (int i = 0; i < nbrUsers; i++) {
System.out.println("Create user >>>>" + i);
}
return true;
} catch (Exception e) {
System.out.println("Exception " + e);
return false;
}
}
}
It still show me the result like this in Output netbeans:
...
Infos: This task is planified to execute at Wed Nov 16 14:40:29 GMT+01:00 2016
Infos: -------------->1
Infos: Create user >>>>0
Infos: Creation ------------Success------------
...
Someone have an idea about this issue?
Thank you.
In GlassFish (in JavaEE in general), you should use the TimerService from the EJB specification for scheduling. I assume you are using java.util.Timer, which just runs in a separate thread. GlassFish does not know anything about the thread, so it cannot stop it with undeploy.
You should rewrite your Singleton to something like this:
#Singleton
#Startup
public class StartWhenDeploy {
private static final int PERIOD = 3000;
// Inject the TimerService into this EJB
#Resource
private TimerService timer;
private TimerAction action;
#PostConstruct
public void init() {
System.out.println("I will set information to start my task");
// the action object is created before the timer
action = new TimerAction(1);
timer.createTimer(new Date(), PERIOD, "My timer");
}
// this method will be executed when the timer fires - it needs to wrap your `TimerAction` created once per this singleton instance (`TimerAction` does not have to extend `TimerTask` now)
#Timeout
public void runTimerAction() {
action.run();
}
}
TimerTask spawns a new thread whose lifecycle is unaffected by undeploying your application.
A better way to do this would be to use a proper EJB timer with #Schedule like this example:
#Singleton
#Startup
public class SimpleTimerBean {
static Logger logger = Logger.getLogger(SimpleTimerBean.class.getCanonicalName());
#Schedule(hour = "*", minute = "*", second = "*/3", info = "Create user every 3 seconds", timezone = "UTC")
public boolean createUser() {
try {
System.out.println("-------------->" + nbrUsers);
for (int i = 0; i < nbrUsers; i++) {
System.out.println("Create user >>>>" + i);
}
return true;
} catch (Exception e) {
System.out.println("Exception " + e);
return false;
}
}
}
I am using Quartz CronScheduler to execute a job every 15 minutes. Every time the job executes it checks the DB for any change in the cron expression and updates the job scheduler for the next run. I have implemented the above in the following way:
#Service
public class QuartzSchedulerService {
private static final Logger LOG = LoggerFactory.getLogger(QuartzSchedulerService.class);
private Scheduler scheduler;
#PostConstruct
private void init() {
try {
scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
} catch (Exception e) {
LOG.error("Unable to start quartz scheduler", e);
}
}
#PreDestroy
private void destroy() {
try {
scheduler.shutdown();
} catch (Exception e) {
LOG.error("Unable to shutdown quartz scheduler", e);
}
}
public void registerCronJob(Class<? extends Job> jobClass, String cronExpression) {
try {
String jobName = jobClass.getSimpleName();
CronScheduleBuilder cronBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName).build();
CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(jobName).withSchedule(cronBuilder).build();
scheduler.scheduleJob(jobDetail, cronTrigger);
LOG.info("Registered Cron Job:" + jobName + " " + jobDetail.getKey());
} catch (Exception e) {
LOG.error("Unable to register cron job", e);
}
}
public void updateCronSchedule(Class<? extends Job> jobClass, String cronExpression) {
try {
String jobName = jobClass.getSimpleName();
CronScheduleBuilder cronBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
CronTrigger newCronTrigger = TriggerBuilder.newTrigger().withIdentity(jobName).withSchedule(cronBuilder).build();
scheduler.rescheduleJob(TriggerKey.triggerKey(jobName), newCronTrigger);
LOG.info("Updated Cron Job:" + jobName + " " + newCronTrigger.getJobKey());
LOG.info("Jobs executed: " + scheduler.getMetaData().getNumberOfJobsExecuted());
} catch (Exception e) {
LOG.error("Unable to reschedule cron job", e);
}
}
}
The class which implements the Job interface is as belows:
#Component
#DisallowConcurrentExecution
public class PropertiesReloadJob implements Job {
private static final Logger LOG = LoggerFactory.getLogger(PropertiesReloadJob.class);
#Autowired
private QuartzSchedulerService schedulerService;
#Autowired
private PropertiesService propertiesService;
public void loadAtStartup() {
load();
LOG.info("--- Registerting PropertiesReload Cron Job ---");
schedulerService.registerCronJob(PropertiesReloadJob.class, propertiesService.getCacheReloadCronExpression());
}
#Override
public void execute(JobExecutionContext context) throws JobExecutionException {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
load();
LOG.info("--- Updating Pro Cron Job ---");
schedulerService.updateCronSchedule(PropertiesReloadJob.class, propertiesService.getCacheReloadCronExpression());
}
public void load(){
// Load properties from DB
}
The loadAtStartup() method is called during context initializtion and then after every 15 minutes the execute() method is called.
The cron expression used is: 0 0/15 * 1/1 * ? *
Now, the problem is as follows:
Lets say that the job starts at 3:00:00, it will execute as many times it can till 3:00:01, rather than executing only once.
Next the job will start at 3:15:00 and again will run as many times it can till 3:15:01.
The number of times the job executes is different every time.
I am not sure what is causing this behaviour. I have tested the cron expression with cronmaker.
Can somebody point out the error here ?