spring schedule Implementation Dynamic Configuration Execution Time

  • 2021-12-05 06:23:28
  • OfStack

Directory spring schedule Dynamic Configuration Execution Time @ schedule Annotation Dynamic Configuration Time Interval

spring schedule Dynamic Configuration Execution Time

Previously, saas platform realized dynamic modification of timing task time, They are all implemented through the framework of xx-job. In this way, we can manage the timing tasks of our whole saas platform with a single service, but a small project recently done for the bank needs localized deployment, so I don't want to get a lot of services, and they don't require immediate effect after modification, so I directly adopted spring schedule combined with mysql to dynamically configure the execution time.

The schedule we used before can only use static corn expressions by annotation. If we want to realize dynamic SchedulingConfigurer, we need to realize it by annotation @ EnableScheduling. As follows:


package com.zqf.marketing.task;  
import com.zqf.db.marketingrobot.sys.model.RobotSysSwitch;
import com.zqf.marketing.sys.service.SwitchService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service; 
import java.util.Date;
 
/**
 * @author zhenghao
 * @description
 * @date 2019/1/22 21:50
 */
 
@Lazy(false)
@Service
@EnableScheduling
public class TestTaskService implements SchedulingConfigurer { 
    private static Logger log = LoggerFactory.getLogger(TestTaskService.class);
    @Autowired
    private SwitchService switchService; 
 
    private String SpringDynamicCronTask() {
        String cron = "0/5 * * * * ?";
        // Object to get the configuration from the database corn Expression 
        RobotSysSwitch switchById = switchService.getSwitchById(5L);
        cron = switchById.getSwitchFlag();
        log.info(cron);
        return cron;
    } 
 
    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        scheduledTaskRegistrar.addTriggerTask(new Runnable() {
            @Override
            public void run() {
                //  Task logic 
                log.info("task_task_tak");
            }
        }, new Trigger() {
            @Override
            public Date nextExecutionTime(TriggerContext triggerContext) {
                String s = SpringDynamicCronTask();
                //  Task triggering, which can modify the execution cycle of a task 
                CronTrigger trigger = new CronTrigger(s);
                Date nextExec = trigger.nextExecutionTime(triggerContext);
                return nextExec;
            }
        });  
    }
}

In this way, we can dynamically modify the execution time of task, the effective time is, the execution cycle of the last task, and we can also meet our current needs, so that the internship project can be more flexible!

@ schedule annotation dynamic configuration interval

Dynamic configuration time interval is realized by registering tasks to task scheduling, and changing the next scheduling time interval during each scheduling. If tasks are blocked or hung up, they will not be scheduled again. If the setting time is too long, it will take a long time to wait for the next scheduling.


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.PeriodicTrigger;
import org.springframework.stereotype.Component; 
import java.util.Date; 
 
@Component
@EnableScheduling
public class DynamicScheduleTaskSecond implements SchedulingConfigurer {
    private static final long WEEK_MILLIS = 604800000;
    private static final long MIN_MILLIS = 1000;
    private static long period = 1000;
    static long l = System.currentTimeMillis(); 
    @Autowired
    SetPeriod setPeriod;
 
    public static long getPeriod() {
        return period;
    }
 
    public static void setPeriod(long period) {
        DynamicScheduleTaskSecond.period = period;
    }
 
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.addTriggerTask(new Runnable() {
            @Override
            public void run() {
                try {
                    setPeriod.update(period);
                    System.out.println("abc");
                    Long last = System.currentTimeMillis() - l;
                    l = System.currentTimeMillis();
                    System.out.println(last);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, new Trigger() {
            @Override
            public Date nextExecutionTime(TriggerContext triggerContext) {
                if (period < MIN_MILLIS || period > WEEK_MILLIS)
                    period = MIN_MILLIS;
                PeriodicTrigger periodicTrigger = new PeriodicTrigger(period);
                Date nextExecDate = periodicTrigger.nextExecutionTime(triggerContext);
                return nextExecDate;
            }
        });
    }
}
 
import org.springframework.stereotype.Component; 
@Component
public class SetPeriod { 
    private static Long maxPeriod = 1000l; 
    public void update(Long period) {
        maxPeriod += 1000;
        setScheduleConfig(maxPeriod);
    }
 
    public boolean setScheduleConfig(Long period) {
        DynamicScheduleTaskSecond.setPeriod(period);
        return true;
    }
}

The above is a simple example to realize dynamic scheduling, and the following is the basic principle.

The function of dynamic scheduling is mainly to realize the functional interface of SchedulingConfigurer, and the parameters of configureTasks in the interface are the key points.


@FunctionalInterface
public interface SchedulingConfigurer { 
 /**
  * Callback allowing a {@link org.springframework.scheduling.TaskScheduler
  * TaskScheduler} and specific {@link org.springframework.scheduling.config.Task Task}
  * instances to be registered against the given the {@link ScheduledTaskRegistrar}.
  * @param taskRegistrar the registrar to be configured.
  */
 void configureTasks(ScheduledTaskRegistrar taskRegistrar); 
}

Look at the name ScheduledTaskRegistrar to know that it is a scheduling task registration class, and calling the addTriggerTask method of this class requires two parameters


    public void addTriggerTask(Runnable task, Trigger trigger) {
        this.addTriggerTask(new TriggerTask(task, trigger));
    }

One is the task thread, and the last one is the second Trigger, which is an interface for setting the trigger time of tasks. The specific implementation has two classes, one is the time setting of CronTrigger corresponding to cron type, and the other is the time setting of FixDelay and FixRate corresponding to FixDelay and FixRate, which are used in the example.


public interface Trigger {
    @Nullable
    Date nextExecutionTime(TriggerContext var1);
}

The interface method parameter is an TriggerContext, This parameter is the context of the task trigger, It stores the start time, end time and actual execution time of the last task, I need to implement this nextExecutionTime method to return a new Date time according to the last task execution time. The new1 new periodicTrigger objects initialize the period time interval to a new time interval, and the nextExecutionTime method can return a new task scheduling time according to the context time. However, the time of period can't be too long or too short, so it is best to set an interval, which can avoid the trouble caused by many careless errors, and perfectly solve the function of dynamically setting task scheduling time interval.

Let's talk about what needs to be done in the first thread task. The tasks performed need to be implemented in other concrete classes, Then call in this thread, and then reset the time interval according to the time service every time when scheduling tasks, such as changing the time interval after reading the configuration, that is, scheduling and specific tasks form a ring, and after scheduling and executing specific tasks, specific tasks set the scheduling time interval.


Related articles: