In the project, it is necessary to configure Scheduled tasks to collect hdfs-jmx data for reading and writing database operations, and configure some Scheduled tasks for alarm operations. The @ Scheduled annotation is used.
When 7 scheduled tasks are configured every 5s according to the end time, a problem is found that some scheduled tasks are not executed on time, but they are not executed every time, nor are they executed by the same thread every time. It's strange. I went to see what's going on
Some scheduled task codes configured in the project are as follows:
@Scheduled(fixedDelay = 5000) public void updateTotalDifference() throws IOException { summaryController.updateTotalDifference(); } @Scheduled(fixedDelay = 5000) public void update1() throws IOException { dataNodeController.updateDNGroupFirst(); } @Scheduled(fixedDelay = 5000) public void update2() throws IOException { dataNodeController.updateDNGroupSecond(); } @Scheduled(fixedDelay = 5000) public void update3() throws IOException { summaryController.updateNNActiveAndStandby(); }
I found that the program occasionally updates DN but not NN, occasionally updates NN but not DN, and the alarm timing task executed every 30s and every 1h will be executed every time. In order to find the reason, you need to look at the @ Scheduled source code
* * <p>Processing of {@code @Scheduled} annotations is performed by * registering a {@link ScheduledAnnotationBeanPostProcessor}. This can be * done manually or, more conveniently, through the {@code <task:annotation-driven/>} * element or @{@link EnableScheduling} annotation. *
Translation:
{@ code@scheduledAnotationBeanPostProcessor }The processing of is performed by registering {@ link scheduledanotionbeanpostprocessor}. This may be done manually, or more conveniently through {@ code < task: annotation driven / >} elements or @ {@ link enableshcheduling} annotations.
Through this comment, we can find that every method marked by @ Scheduled annotation will be registered as a ScheduledAnnotationBeanPostProcessor. Then, we will look at what is ScheduledAnnotationBeanPostProcessor:
/** * Set the {@link org.springframework.scheduling.TaskScheduler} that will invoke * the scheduled methods, or a {@link java.util.concurrent.ScheduledExecutorService} * to be wrapped as a TaskScheduler. * <p>If not specified, default scheduler resolution will apply: searching for a * unique {@link TaskScheduler} bean in the context, or for a {@link TaskScheduler} * bean named "taskScheduler" otherwise; the same lookup will also be performed for * a {@link ScheduledExecutorService} bean. If neither of the two is resolvable, * a local single-threaded default scheduler will be created within the registrar. * @see #DEFAULT_TASK_SCHEDULER_BEAN_NAME */ public void setScheduler(Object scheduler) { this.scheduler = scheduler; }
Translated as:
Set {@ link org.springframework.scheduling.TaskScheduler} that will call the scheduling method, or wrap {@ link java.util.concurrent.ScheduledExecutorService} as a TaskScheduler. If not specified, the default scheduler solution will be applied: search the unique {@ link TaskScheduler}bean in the context, otherwise search the {@ link TaskScheduler}bean named "TaskScheduler"; The same lookup will be performed on the {@ link ScheduledExecutorService}bean. If neither is resolvable, a local single threaded default scheduler is created in the Registrar@ See # default (task) scheduler (BEAN) name
We can find a sentence here: if the TaskScheduler is not specified, the default scheduler solution will be applied: search the unique {@ link TaskScheduler}bean in the context, otherwise search the {@ link TaskScheduler}bean named "TaskScheduler"; The same lookup will be performed on the {@ link ScheduledExecutorService}bean. If neither is resolvable, a local single threaded default scheduler is created in the Registrar.
That is to say, if we do not actively configure the task Scheduler, SpirngBoot will use a single threaded Scheduler by default to process all the scheduled tasks we implement with @ Scheduler annotation. It can be understood that of my seven scheduled tasks, four are at the same time and three are at different times, that is, the four scheduled tasks are executed by single thread, Therefore, a task is not executed occasionally, but not every time
Then we need to create a TaskScheduler and register it in the context:
/** * @author Zenglin.Fang * @ClassName ScheduledTaskConfiguration * @Description: * @Data: 2021/9/4 15:25 **/ @Configuration public class ScheduledTaskConfiguration implements SchedulingConfigurer { /** * Callback allowing a {@link TaskScheduler * TaskScheduler} and specific {@link Task Task} * instances to be registered against the given the {@link ScheduledTaskRegistrar} * * @param taskRegistrar the registrar to be configured. */ @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { final ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); taskScheduler.setPoolSize(10); taskScheduler.initialize(); taskRegistrar.setTaskScheduler(taskScheduler); } }
Here, I created a tashScheduler with a thread pool size of 10. After uploading git and publishing the new version, I found that the problem was solved. The execution of each scheduled task did not affect each other, and all DN and NN could be updated normally.
Finally, attach the @ Scheduled annotation parameter:
Parameter value | effect |
---|---|
cron | cron expression setting timing |
zone | Take the time zone where the server is located, and this field is generally left blank |
fixedDelay | After the last task is completed, execute the next task at an interval of (x/1000) seconds |
fixedDelayString | Consistent with the meaning of fixedDelay, it uses string form and supports placeholders |
fixedRate | The task is executed once every (x/1000) seconds. Whether the last task is completed or not, it can be used in conjunction with initiaDelay |
fixedRateString | Consistent with the meaning of fixedRate, it uses string form and supports placeholders |
initiaDelay | Wait (x/1000) seconds before executing the task for the first time and delay (x/1000) seconds |
initialDelayString | Consistent with the meaning of initialDelay, it uses the form of string and supports placeholders |