How to create multiple instances of a scheduler class in spring boot? - spring-boot

I have a class containing the #Scheduled annotated method.
I want to create multiple instances of a class in spring boot application so that I should be able to run multiple jobs for the specified time period.
I have googled and tried with creating a new object but scheduling didn't work.
Note: I will pass what to execute at runtime for respective instance.

You can create a class with multiple methods to schedule your jobs at same time, doing same job..
#Component
public class Job {
#Scheduled(initialDelay = 1000, fixedDelay = 60000)
public void job1() {
jobWork();
}
#Scheduled(initialDelay = 1000, fixedDelay = 60000)
public void job2() {
jobWork();
}
private void jobWork() {
}
}

#Scheduled is a repatable annotation so you can add multiple #Scheduled in same method:
#Scheduled(initialDelay = 1000, fixedDelay = 60000)
#Scheduled(initialDelay = 1000, fixedDelay = 60000)
public void jobWork() {
jobWork();
}
#Repeatable(value=Schedules.class)
See also Duplication on #Scheduled
Repeating Annotations as #Scheduled allow multiple annotations

Here is the answer,
I implemented ApplicationContextAware
#Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
for (int i =0;i<4;i++) {
((ConfigurableApplicationContext) applicationContext).getBeanFactory()
.registerSingleton("New Instance " + i, new SchedularJob());
}
}
It will create 4 instances of SchedularJob class and 4 schedulers will run independently.

Related

Spring #Schleduled annotation does not work

I want a spring scheduled task, that runs every 10 seconds, however for some reason the task runs only once and is never repeated again.
Please do not suggest me to use other types of tasks, because I need specifically to use spring tasks.
#Scheduled(fixedRate = 10000, initialDelay = 1000)
public void myTask() {
...
}
In my main config class I have #EnableScheduling added as well.
Scheduling is a process of executing the tasks for a specific time period, but you looking to make it asynchrounslly so there will be a couple of changes
create a config class that will manage the Async operations so you make use of ThreadPoolTaskExecutor:
#EnableScheduling
#Configuration
public class TaskConfig implements SchedulingConfigurer {
#Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar)
{
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(10);
threadPoolTaskScheduler.setThreadNamePrefix("your-scheduler-");
threadPoolTaskScheduler.initialize();
scheduledTaskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
}
}
then you can run jobs asynchrounslly as the below :
#Component
public class HelloSender {
#Scheduled(fixedRate = 10000)
public void myTask() {
System.out.println("im running asynchronous with Worker : " + Thread.currentThread().getName());
}
}
for further information about ThreadPoolTaskExecutor please have look here: https://docs.spring.io/spring-framework/docs/3.0.x/spring-framework-reference/html/scheduling.html

How to configure graceful shutdown using DelegatingSecurityContextScheduledExecutorService with Spring

I'm trying to use the new options to do graceful shutdown with spring introduced in version 2.3, but I'm struggling to make my scheduled task to behave the same way.
As I need a valid user in the context during scheduled tasks execution, I am using DelegatingSecurityContextScheduledExecutorService to achieve this goal.
Here is a sample of my implementation of SchedulingConfigurer:
#Configuration
#EnableScheduling
public class ContextSchedulingConfiguration implements SchedulingConfigurer {
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskExecutor());
}
#Bean
public TaskSchedulerCustomizer taskSchedulerCustomizer() {
return taskScheduler -> {
taskScheduler.setAwaitTerminationSeconds(120);
taskScheduler.setWaitForTasksToCompleteOnShutdown(true);
taskScheduler.setPoolSize(2);
};
}
#Bean
public Executor taskExecutor() {
ThreadPoolTaskScheduler threadPool = new ThreadPoolTaskScheduler();
taskSchedulerCustomizer().customize(threadPool);
threadPool.initialize();
threadPool.setThreadNamePrefix("XXXXXXXXX");
SecurityContext schedulerContext = createSchedulerSecurityContext();
return new DelegatingSecurityContextScheduledExecutorService(threadPool.getScheduledExecutor(), schedulerContext);
}
private SecurityContext createSchedulerSecurityContext() {
//This is just an example, the actual code makes several changes to the context.
return SecurityContextHolder.createEmptyContext();
}
#Scheduled(initialDelay = 5000, fixedDelay = 15000)
public void run() throws InterruptedException {
System.out.println("Started at: " + LocalDateTime.now().toString());
long until = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(30);
while (System.currentTimeMillis() < until) {}
System.out.println("Ended at: " + LocalDateTime.now().toString());
}
}
But when I send a termination signal while the sheduled task is running, the application does not wait for the task.
If in my bean taskExecutor I replace the last two lines, returning the ThreadPoolTaskScheduler without a context, everything work as expected. It only doesn't work when I return the DelegatingSecurityContextScheduledExecutorService.
How can I set the context for the taskExecutor and at the same time configure to wait for tasks to complete on shutdown?
I alredy tried several variations of this code, using another implementations of the interfaces TaskScheduler and TaskExecutor, but without success.
For starters cleanup your code and use the proper return types in the bean methods (be specific) and expose both as beans (marking one as #Primary!).
#Configuration
#EnableScheduling
public class ContextSchedulingConfiguration implements SchedulingConfigurer {
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(securitytaskScheduler());
}
#Bean
public ThreadPoolTaskScheduler taskScheduler() {
ThreadPoolTaskScheduler taskScheduler= new ThreadPoolTaskScheduler();
taskScheduler.setAwaitTerminationSeconds(120);
taskScheduler.setWaitForTasksToCompleteOnShutdown(true);
taskScheduler.setPoolSize(2);
taskScheduler.setThreadNamePrefix("XXXXXXXXX");
return taskScheduler;
}
#Bean
#Primary
public DelegatingSecurityContextScheduledExecutorService securitytaskScheduler() {
SecurityContext schedulerContext = createSchedulerSecurityContext();
return new DelegatingSecurityContextScheduledExecutorService(taskScheduler().getScheduledExecutor(), schedulerContext);
}
private SecurityContext createSchedulerSecurityContext() {
//This is just an example, the actual code makes several changes to the context.
return SecurityContextHolder.createEmptyContext();
}
#Scheduled(initialDelay = 5000, fixedDelay = 15000)
public void run() throws InterruptedException {
System.out.println("Started at: " + LocalDateTime.now().toString());
long until = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(30);
while (System.currentTimeMillis() < until) {}
System.out.println("Ended at: " + LocalDateTime.now().toString());
}
}
Important is to be as specific in your return types as possible. Configuration classes are detected early on and the return types are checked to determine the callbacks to be made. Now ThradPoolTaskScheduler is a DisposableBean an Executor is not and will not receive callbacks as such!.

How to use WatchService (NIO Package) & #Scheduled same time in single project of Spring-Boot?

I have written a script in while I have a schedular class that does something in after every certain time interval and another class in which I am watching a folder continuously for the occurance of any new file. And these both jobs (Schedular + WatchService) has to be endless.
But they are not getting called concurrently.
Called schedular class by - #Scheduled & #ComponentScan(basePackages = "com.project.schedular")
Calling WatchService by - #PostConstruct on method
Already tried Putting #PostConstruct on both and putting both packages in #ComponentScan({"com.project.schedular","com.project.watcher"})
Also tried putting #Async on both the methods.
Main Class:
#SpringBootApplication
#EnableScheduling
#ComponentScan(basePackages = "com.aprstc.schedular")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Component
public class SchedularClass {
#PostConstruct
#Scheduled(fixedRate = 30000)
public void execute() {
//logic of scheduling method
}
Watcher Class:
#Component
public class WaybillReadScript {
#PostConstruct
public void watchFolder() throws InterruptedException, IOException {
System.out.println("Into the watch Folder.");
WatchService watchService = FileSystems.getDefault().newWatchService();
System.out.println(2);
Path path = Paths.get("/home/mypc-630/Work/abc");
System.out.println(3);
try {
path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);
} catch (IOException e) {
e.printStackTrace();
}
WatchKey key;
while ((key = watchService.take()) != null) {
for (WatchEvent<?> event : key.pollEvents()) {
if (event.context().toString().equalsIgnoreCase("wbill.txt"))
processWaybillFile();
}
key.reset();
}
}
}
I expect that both classes must run concurrently.
Watcher Must do continuous watching.
And the scheduler must do a continuous scheduled job.
I think the PostConstruct is the wrong place. PostConstruct is used to initialize your beans/components. And if you make a blocking call with watchService.take(), this PostContruct will never be left and if not all beans are completely created than your application with the scheduler will not start.

Spring-Boot with Quartz and multiple schedulers

I am working with a scenario where we have one database with multiple schemas, one schema for each customer. This allows each customer to set different schedules for their jobs. All schemas have the same set of jobs, only the schedules differ.
I need to write one Spring-Boot app to run all jobs from all schemas.
It seems like this would be done by defining different quartz.properties for each schema, and then configuring a different Scheduler for each one, like this:
#SpringBootApplication
#Configuration
public class MyApplication{
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
#Bean
public Scheduler schedulerA(Trigger trigger, JobDetail job) {
StdSchedulerFactory factory = new StdSchedulerFactory();
factory.initialize(new ClassPathResource("quartzA.properties").getInputStream());
Scheduler scheduler = factory.getScheduler();
scheduler.setJobFactory(springBeanJobFactory());
scheduler.scheduleJob(job, trigger);
scheduler.start();
return scheduler;
}
#Bean
public Scheduler schedulerB(Trigger trigger, JobDetail job) {
StdSchedulerFactory factory = new StdSchedulerFactory();
factory.initialize(new ClassPathResource("quartzB.properties").getInputStream());
Scheduler scheduler = factory.getScheduler();
scheduler.setJobFactory(springBeanJobFactory());
scheduler.scheduleJob(job, trigger);
scheduler.start();
return scheduler;
}
}
My question is, is this correct? Can I just define these schedulers in my SpringBootApplication class annotated with #Configuration, and expect it to work (assuming the properties are correct)? Am I missing anything?
My question is, is this correct? Can I just define these schedulers in
my SpringBootApplication class annotated with #Configuration
This is correct. Alternatively you can use Spring #Schelduled annotation with a Cron defined in properties files.
#Scheduled(cron = "0 15 10 15 * ?")
public void scheduleTaskUsingCronExpression() {
.
.
.
But, if you want more control over the jobs like failover, retry policy or track and run/rerun jobs from a dashboard. Think of spring-batch
Inspired by the above example I found a way to use configurations managed in application properties which seems to be easier and more consistent with the rest of the Spring-Boot app. It is particularly useful to reuse the data source configuration. Any number of beans of the second kind is possible.
#Configuration
class MainQuartzConfiguration {
/**
* Main scheduler bean where all jobDetails, calendars and trigger beans are attached.
*
*/
#Primary #Bean
public SchedulerFactoryBean mainScheduler(QuartzProperties properties,
ObjectProvider<SchedulerFactoryBeanCustomizer> customizers,
ObjectProvider<JobDetail[]> jobDetails, Map<String, Calendar> calendars,
ObjectProvider<Trigger[]> triggers, ApplicationContext applicationContext) {
SchedulerFactoryBean factory = new QuartzAutoConfiguration(properties, customizers, jobDetails, calendars, triggers, applicationContext)
.quartzScheduler();
factory.setSchedulerName("mainScheduler");
return factory;
}
}
#Configuration
class AnotherConfiguration {
/**
* Second scheduler bean which has the same configuration but different thread count and thread priority.
*/
#Bean
SchedulerFactoryBean secondScheduler(
QuartzProperties properties,
ObjectProvider<SchedulerFactoryBeanCustomizer> customizers,
#Value("${spring.quartz.properties.secondScheduler.org.quartz.threadPool.threadPriority:7}") int threadPriority,
#Value("${spring.quartz.properties.secondScheduler.org.quartz.threadPool.threadCount:1}") int threadCount,
ApplicationContext applicationContext)
{
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
SpringBeanJobFactory jobFactory = new SpringBeanJobFactory();
jobFactory.setApplicationContext(applicationContext);
schedulerFactoryBean.setJobFactory(jobFactory);
schedulerFactoryBean.setSchedulerName("secondScheduler");
schedulerFactoryBean.setAutoStartup(properties.isAutoStartup());
schedulerFactoryBean
.setStartupDelay((int) properties.getStartupDelay().getSeconds());
schedulerFactoryBean.setWaitForJobsToCompleteOnShutdown(
properties.isWaitForJobsToCompleteOnShutdown());
Properties propertiesVariant = new Properties();
propertiesVariant.putAll(properties.getProperties());
propertiesVariant.setProperty("org.quartz.threadPool.threadPriority", Integer.toString(threadPriority));
propertiesVariant.setProperty("org.quartz.threadPool.threadCount", Integer.toString(threadCount));
schedulerFactoryBean.setQuartzProperties(propertiesVariant);
schedulerFactoryBean.setJobDetails(CatalogBenchmarkJob.createJob());
customizers.orderedStream().forEach(
(customizer) -> customizer.customize(schedulerFactoryBean));
return schedulerFactoryBean;
}
}

Spring Scheduler

I go through spring Scheduler support documentation.
where I found:
ScheduledFuture schedule (Runnable task, Date startTime);
But in case of #EnableScheduling there is no Thread Implementation in various examples.
Why??
any one can explain
Thanks in advance.
With #EnableScheduling you just enable the spring scheduler functionality.
To run a task you would annotate a public method with #Scheduled.
So you see that you dont need a runnable / thread for this as your annotabed method will be called using reflection.
#EnableScheduling
public class Tasks {
#Scheduled(... options here)
public void myTasks(){
//doSomethingHere...
}
}
our class must have at least these annotations :
package org.springframework.scheduling.annotation
#Configuration
#EnableScheduling
you can set it with a fixedDelay
#Scheduled(fixedDelay = 1000)
with initialDelay also:
#Scheduled(fixedDelay = 1000, initialDelay = 1000)
or with a fixedRate (when each execution of the task is independent)
#Scheduled(fixedRate = 1000)
you can also create it on runtime using
org.springframework.scheduling.annotation.SchedulingConfigurer
public class SchedulerContextconfig implements SchedulingConfigurer
#Override
public void configureTasks(ScheduledTaskRegistrar register) {
register.addCronTask(Runnable task, String expression)
}

Resources