Spring #Schleduled annotation does not work - spring

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

Related

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.

Making scheduler application specific and not server specific

We have to bind the scheduler Thread to application context.
I tried using #PostConstruct but it starts the scheduler once application is up but it keeps running in the background even if application is down and server is up.
If application is down then the scheduler should also stop.
The way I used Scheduler in Spring (i.e. Spring Boot) is by having two classes inside my project (& therefore included in my .jar after build).
1 - SchedulerConfig (necessary for the configuration)
#Configuration
public class SchedulerConfig implements SchedulingConfigurer {
private final int POOL_SIZE = 10;
#Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(POOL_SIZE);
threadPoolTaskScheduler.setThreadNamePrefix("my-scheduled-task-pool-");
threadPoolTaskScheduler.initialize();
scheduledTaskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
}
}
2 - ScheduledTasks (the actual scheduled tasks with frequency defined by the cron expression)
#Component
public class ScheduledTasks {
private static final Logger LOG = Logger.getLogger(ScheduledTasks.class);
#Scheduled(cron = "0 0 * ? * *")
public void doSomething() {
// Do something
}
}
Therefore, as everything is included in the running .jar, when the application is not deployed any more, scheduled tasks will not run as well.
See also https://www.baeldung.com/spring-scheduled-tasks

How to create multiple instances of a scheduler class in 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.

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