Spring Boot implements scheduled tasks

Just add @enablesCheduling to the class and @scheduled to the methods to enable Scheduled tasks

Spring Boot provides scheduled tasks

@EnalbleScheduling

@enablescheduling can be placed in the boot class, convenient overall control.

@Scheduled several properties

Different attributes have different effects

FixedDelay Time since the last task

Effect: How long has it been since the last task

@Slf4j @Component @EnableScheduling public class TaskOne { @Scheduled(fixedDelay = 2 * 1000) public void taskOne(){ log.info("taskOne Begin..." ); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } log.info("task One End..." ); }}Copy the code

The next task starts at the fixedDelay interval after the last task ends

FixedRate: Time between the start of the last task and the start of the next task

@Scheduled(fixedRate = 5 * 1000)
Copy the code

The next task executes after the fixedRate interval since the start of the previous task, regardless of whether the previous task executes longer than the interval

However, spring Boot’s scheduled tasks are single-threaded by default. Even if the next task has waited longer than the fixedRate time since the last task started, it still waits for the last task to complete.

  • FixDelay Time between the end of a task and the start of the next task
  • FixRate The interval between the start of the previous task and the start of the next task

How can I solve the problem that the waiting time of the next task exceeds the fixedRate time and waits for the last task to complete?

Specify a thread pool for timed tasks, each task runs in a separate thread, and there is no waiting for the last task. The question becomes how do you configure SpringBoot timed tasks to be multithreaded?

InitialDelay: The number of seconds to start the first task

Both fixedDelay and fixedRate are executed immediately after the project starts and then repeated at specified intervals. To delay the execution of the first task, use initialDelay

@Scheduled(fixedRate = 5 * 1000,initialDelay = 2 * 1000)
Copy the code

Cron: timed execution (most commonly used)

Cron expression, generally write 6 bits can be. @schedule (cron = “Schedule(cron =” Schedule(cron = “day, month, week [year]”)

Cron expression utility rules:

*/number indicates “every nubmer”

The comma indicates “or”. For example, 12,13,16 indicates 12,13, or 16

Online Cron generator: www.pppet.net/

A hole in the line

@Slf4j @Component @EnableScheduling public class TaskOne { @Scheduled(cron = "*/10 * * * * ?" ) public void taskOne(){ log.info("taskOne Begin..." ); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } log.info("taskOne End..." ); } @Scheduled(cron = "*/10 * * * * ?" ) public void taskTwo(){ log.info("taskTwo Begin..." ); try { TimeUnit.SECONDS.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } log.info("taskTwo End..." ); }}Copy the code

Multiple scheduled tasks are enabled at the same time. If a scheduled task takes a long time to execute or is stuck, other scheduled tasks are waiting. Why?

Spring Boot Scheduled tasks are single-threaded by default.

SpringBoot Timing task configuration multi-threading:

/** * thread pool configuration ** / @enableAsync // @configuration public class ThreadPoolTaskConfig implements WebMvcConfigurer {@bean ("taskExecutor") public Executor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(3); executor.setMaxPoolSize(3); executor.setQueueCapacity(5); executor.setKeepAliveSeconds(10); executor.setThreadNamePrefix("async-task-"); / / thread pool of reject the task processing policy executor. SetRejectedExecutionHandler (new ThreadPoolExecutor. CallerRunsPolicy ()); // Initialize executor.initialize(); return executor; }}Copy the code

Then add @async (“taskExecutor”) to the scheduled task,

Multiple thread pools may be configured in a project, and it is a good practice to create a thread pool with a meaningful name, dedicated to the pool. There is still a problem, but once a task is completed, the thread will randomly execute a task, and when it gets to task 2, the thread will get stuck in task 2. Eventually all threads stuck in task 2

How do I ensure scheduled tasks are available

When a scheduled task is abnormal, the scheduled task pool cannot be configured. Eventually, the thread pool will still be exhausted, causing all threads to block unless there is a dedicated thread pool for each scheduled task.

Therefore, the most important thing is to detect and rectify the abnormal time consumption of scheduled tasks in time.

When configuring a thread pool, you can specify a denial policy that is triggered when the thread pool queue is full.

How do YOU replace thread pools in Spring scheduled tasks?

SpringBoot exposes three methods for customizing the scheduled task pool:

  • If a Bean of type SchedulingConfigurer exists, use SchedulingConfigurer
  • If there is a TaskSheduler type Bean, use TaskScheduler
  • If ScheduledExecutorService beans exist, ScheduledExecutorService is used
  • None of the above are used by default

Either of the above timed task thread pools calls ScheduledTaskRegistrar#setScheduler to assign a value to the taskScheduler.

In practice, it is recommended to use a custom rejection policy. Why?

If the thread pool is not enough, can I run the main thread directly? If the main thread is blocked, can I just drop it? If the business itself doesn’t care if the request fails, then it doesn’t matter, otherwise a discard strategy is not appropriate.

You can use the message queue (delay buffering) or email alarm (timely discovery) in a customized discarding policy. You only need to implement the RejectedExecutionHandler interface:

@Configuration @EnableAsync @Slf4j public class ThreadPoolTaskConfig { @Bean("executor") public Executor getExecutor(){ ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(3); executor.setMaxPoolSize(3); executor.setQueueCapacity(5); executor.setKeepAliveSeconds(10); executor.setThreadNamePrefix("async-task-"); / / thread pool of reject the task processing policy executor. SetRejectedExecutionHandler ((r, executor1) - > {the info (" email warning = = = = = = > : hey, Executor1.getqueue ().size()); executor1.executor1.getQueue ().size()); executor1.executor1.getQueue ().size()); }); // Initialize executor.initialize(); return executor; }}Copy the code

In this way, you have a complete alarm mechanism to detect online problems in time.

When a project is deployed on multiple nodes, repeated execution on different nodes needs to be considered. This is where you need to consider using distributed locks, but with distributed locks, you need to consider whether deadlocks can occur.

Disadvantages of Spring Boot scheduled tasks:

  • A single node cannot be started in a cluster (different nodes may perform the same scheduled task repeatedly)
  • Sharding tasks are not supported
  • Failed retry is not supported (a task that fails fails and will not be retried)
  • Dynamic adjustment is cumbersome (configuring the start time of dynamic configuration tasks is complicated)

Suggestion: In a distributed project with multiple nodes deployed, use elastice-job or xxl-job

The thread pool above is not strictly a Scheduled task thread pool, but an asynchronous task thread pool. Scheduled tasks theoretically only need to add @scheduled, and @async does not need to be specified. @async is related to asynchronous threads.

This article is part of the “Gold Nuggets For Free!” Activity, click to viewEvent details