In those years, we used “scheduled scheduling”

Time:2019-8-13

Timing Scheduling

As back-end developers, we always encounter business scenarios such as synchronizing batches of data every week, checking the status of the server every half an hour, sending an e-mail to the user at 8:00 a.m. every day, and so on.

These scenarios are inseparable from the “timer”, like an alarm clock with a fixed time rule, which triggers at a specified time to perform the scheduling tasks we want to define. So let’s count today the “scheduled scheduling” we used in those years.

1. job (oracle)

Oracle database has been used since the beginning of work, the earliest contact with the timing task is Oracle database job. Job has the function of regular execution and can perform tasks on its own at specified time points or at certain time points of the day. And when Oracle restarts, job will continue to run without restarting.

Moreover, the mechanism of job is very complete. It can query related tables or views, and query the timing rules and execution of job. The disadvantage is that as an Oracle database level tool, custom function expansion, secondary development is more difficult.

1.1 Create jobs

DECLARE
  job NUMBER;
BEGIN
    sys.dbms_job.submit(job => job,

    What =>'prc_name;', -- the name of the stored procedure executed

    Next_date=> to_date ('22-11-2013 09:09:41','dd-mm-yyyyyhh24:mi:ss') -- next execution time

    Interval =>'sysdate + 1/24'; -- run prc_name process 24 hours a day, that is, once an hour
END;

The job parameter is the output parameter, and the binary_ineger returned by the submit () procedure is used to uniquely identify a job. Generally, a variable reception is defined, and the job value can be queried from the user_jobs view.
-- What parameter is the PL/SQL code block to be executed, the name of the stored procedure, and so on.
The next_date parameter indicates when the job will run.
-- When will the interval parameter be re-executed?

1.2 Delete job

DECLARE
BEGIN
  Dbms_job.remove (1093); 1093 is the current job value to be deleted
  COMMIT;
END;

1.3 Query job

Query the job of the current user
select * from user_jobs;
- Query all jobs
select * from dba_jobs;
- Query all running jobs
select * from dba_jobs_running;

2. crontab (linux)

Crond is a daemon used under Linux to periodically perform certain tasks or wait for certain events to be processed. It is similar to the scheduled tasks under windows. When the operating system is installed, the service tool will be installed by default, and the crond process will be started automatically. The crond process will check periodically every minute whether it has to be executed or not. Tasks are automatically executed if there is a task to be executed.

Cron is the name of the service, crond is the background process, and crontab is the customized schedule. Most Linux systems have cron installed by default, which can be checked.

Check whether Crontab tools are installed
crontab -l
Check whether the crond service is started
service crond status

CentOS installation
yum install vixie-cron
yum install crontabs

Crontab Basic Operating Command

List the details of a user's cron service
crontab -l
Edit a user's cron service
crontab -e

Crontab expression format

{minute} {hour} {day-of-month} {month} {day-of-week} {full-path-to-shell-script}

 Minute: interval 0-59
 Hour: The interval is 0-23
 Day-of-month: interval 0-31
 Month: The interval is 1 - 12. 1 is January. 12 is December.
 Day-of-week: The interval is 0-7. Sundays can be 0 or 7.

In the above fields, the following special characters can also be used:
Asterisk (*): Represents all possible values, for example, if the month field is an asterisk, it means that the command operation is executed monthly after meeting the constraints of other fields.
Comma (,): You can specify a list range with comma-separated values, such as, "1, 2, 5, 7, 8, 9"
Bar (-): A range of integers can be represented by bars between integers, such as "2-6" for "2,3,4,5,6"
Positive and oblique (/): The interval frequency of the time specified by the positive and oblique lines, such as "0-23/2", can be used to indicate that it is executed every two hours. At the same time, the forward and slash lines can be used with asterisks, such as */10, if used in the minute field, indicating that they are executed every ten minutes.

Recommend a checking website for crontab expressions (https://tool.lu/crontab/)

3. Timer and Scheduled Executor Service (java)

Timer is a timer tool provided in jdk. When it is used, a separate thread outside the main thread will execute the specified scheduled tasks, which can be specified to execute once or repeatedly.

// Execute only once
public void schedule(TimerTask task, long delay);
public void schedule(TimerTask task, Date time);
// Loop execution
// In the cycle execution category, it can be divided into two categories according to the cycle time interval.
public void schedule(TimerTask task, long delay, long period) ;
public void schedule(TimerTask task, Date firstTime, long period) ;
 
public void scheduleAtFixedRate(TimerTask task, long delay, long period)
public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period)

TimerTask is an abstract class that implements the Runnable interface, representing a task that Timer can perform. The TimerTask class is an abstract class arranged by Timer for tasks that are executed once or repeatedly. It has an abstract method, run (), which is used to perform operations to be performed by the corresponding timer task. So each specific task class must inherit TimerTask and then override the run () method.
In addition, it has two non-abstract methods.

- Cancel this timer task
boolean cancel()
- Returns the scheduled execution time of the most recent actual execution of this task
long scheduledExecutionTime()

Of course, Timer is generally used less, because its shortcomings are obvious:

  1. Single thread, when multiple timers run at the same time, will wait for one execution to complete, and then execute the next.
  2. Timer threads do not catch exceptions, and if TimerTask throws unchecked exceptions, the Timer threads will terminate.

So Scheduled Executor Service is usually used instead of Timer.
Scheduled Executor Service: Also a timed task class based on thread pool design that comes with jdk. Each scheduling task is assigned to a thread in the thread pool to execute, so its tasks are executed concurrently without affecting each other.

4. SpringTask (spring)

Timer and Scheduled Executor Service are classes that implement timing scheduling at JDK level. Their functions are not enough to satisfy us. Now we introduce Spring Task, a relatively perfect timing scheduling tool, which is provided by Spring. It supports annotations and configuration file forms, crontab expressions, and is simple but powerful. Big. Personally, I like Spring Task very much just because it supports crontab expressions.

It’s very simple to use in spring boot.

  1. Startup class adds annotation @EnableScheduling for open timing scheduling
  2. On methods that require regular execution, add the annotation @Scheduled (cron = crontab expression)

The default simple usage steps are only two steps above, but SpringTask’s default usage also has some shortcomings:

  1. The default poolsize of the thread pool is 1, which can be understood as a Timer-like single-threaded mode.
  2. The crontab expression cannot be dynamically modified. The modification can only take effect after redeployment.

The solution to Problem 1 is to modify the current thread pool by customizing TaskExecutor. Question 2, you can directly use the threadPoolTaskScheduler class to implement custom timing scheduling rules.

Attached source code TaskTimer. class to solve two problems

@Component
public class TaskTimer {

    @Autowired
    private ThreadPoolTaskScheduler threadPoolTaskScheduler;
    @Autowired
    private TaskRepo taskRepo;

    /**
     * *** Timing Engine***
     *
     * Instantiate a thread pool task scheduling class
     * The default pool Size of ThreadPool Task Scheduler is 1, similar to the single-threaded mode of new Single ThreadExecutor, which can only execute one schedule and then other schedules.
     * You need to customize the extension poolSize to allow a certain degree of multithreaded parallel scenarios
     *
     * @return
     */
    @Bean
    public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
        ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
        threadPoolTaskScheduler.setPoolSize(100);
        threadPoolTaskScheduler.setThreadNamePrefix("Thread - ");
        threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown(true);
        threadPoolTaskScheduler.setAwaitTerminationSeconds(60);
        return threadPoolTaskScheduler;
    }

    /**
     * Start Timing Scheduling
     * @param taskCode
     * @param cron
     * @param runnable
     * @return
     */
    public boolean start(String taskCode, String cron,Runnable runnable){
        ScheduledFuture<?> currentFuture=taskRepo.findTask(taskCode);
        // Existing schedules cannot be created
        if(currentFuture!=null){
            Throw new Runtime Exception ("Scheduling""+taskCode+""Existing, unable to create");
        }
        // Create a new schedule and add taskMap
        currentFuture = threadPoolTaskScheduler.schedule(runnable,new CronTrigger(cron));
        if (currentFuture!=null){
            this.taskRepo.addTask(taskCode,currentFuture);
            return true;
        }
        Throw new Runtime Exception ("Mission Start Failed!!! "";
    }

    /**
     * Suspension Timing Scheduling
     * @param taskCode
     * @return
     */
    public boolean stop(String taskCode) {
        // taskId does not exist, can not stop, can only be modified
        ScheduledFuture<?> currentFuture=this.taskRepo.findTask(taskCode);
        if(currentFuture!=null){
            return currentFuture.cancel(true);
        }
        return true;
    }

    /**
     * Delete Timing Scheduling
     * @param taskCode
     * @return
     */
    public boolean remove(String taskCode){
        ScheduledFuture<?> currentFuture=this.taskRepo.findTask(taskCode);
        if(currentFuture!=null){
             currentFuture.cancel(true);
             taskRepo.removeTask(taskCode);
             return true;
        }
        return false;
    }

    /**
     * Modify Timing Scheduling
     * @param taskCode
     * @param cron
     * @param runnable
     * @return
     */
    public boolean update(String taskCode,String cron,Runnable runnable){
        ScheduledFuture<?> currentFuture=this.taskRepo.findTask(taskCode);
        // Existing schedules, stop first, add again, and update the new Scheduled Future
        if(currentFuture!=null) {
            currentFuture.cancel(true);
        }
        currentFuture= threadPoolTaskScheduler.schedule(runnable,new CronTrigger(cron));
        if(currentFuture!=null){
            this.taskRepo.addTask(taskCode,currentFuture);
            return true;
        }
        return false;
    }

}

5. Quartz (Other Products)

Quartz is an open source job scheduling framework written entirely by Java, which provides a simple but powerful mechanism for job scheduling in Java applications. It is a powerful and mature heavyweight product. It also supports load balancing and realizes distributed scheduling.

However, you’ll have to work harder on the installation of Quartz, from which tables to build in the database to how the application should be deployed. For such a huge product, this article does not attach its instructions.

Reference Documents

  • Implementation of Concurrent Timing Task and Dynamic Timing Task in SpringBook

Recommended Today

Write the correct posture of chameleon cross-end components (Part I)

In the chameleon project, there are two ways to implement a cross-end component: using third-party component encapsulation and unified implementation based on chameleon grammar. This article is the first in a series of articles on the correct posture of chameleon cross-end components. Taking encapsulating a cross-end indexList component as an example, it first introduces how […]