preface

National Day idle to nothing, the previous open source a scheduled task scheduling center reconstruction.

Some crontab crashes were encountered during the session

CronTab

Let’s look at the time format for crontab,

Spec refer to the crontab formation format in the Beego Toolbox module:

// The first six fields respectively represent: // second: 0-59 // minute: 0-59 // hour: 1-23 // Date: 1-31 // month: 1-12 // Week: 0-6 (0 indicates Sunday) // Special symbols can also be used: // * : indicates any time //, : For example, in the third end, "2" and "4" are executed. // - : indicates a segment, for example, "1-5" is executed from 1 to 5. // / N: indicates that each N unit is executed once. Also can be written as 1-23/1. / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / 0/30 * * * * * / / 0 on every 30 seconds 43 21 * * * 21:43 Run // 0 15 05 * * * 05:15 Run // 00 17 * * * 17:00 Run // 00 17 * * 1 Run // 00,10 17 * * 0,2,3 This command is executed at 17:00 and 17:10 every Sunday, Tuesday, and Wednesday // 0 0-10 17 1 * * This command is executed from 17:00 to 7:10 every minute // 00 1,15 * 1 This command is executed at 00:00 on the first and 15th days every month // 0 42 4 1 * * Executed at 4:42 p.m. on the first day of every month // 00 21 * * 1-6 Executed from Monday to Saturday at 21:00 p.m. // 0,10,20,30,40,50 * * * * Executed every 10 minutes // 0 */10 * * * * * Executed every 10 minutes // 0 * 1 * * * every minute from 1:0 to 1:59 // 00 1 * * * 1:00 Executed // 00 */1 * * * every hour executed // 00 * * * * 0 when in their implementation of every 1 hour / / 0 2 * * * 8-20/3 8:02, 11:02, 14:02, 17:02, 20:02 / / 0 on 30 May 1 2 * * 1 and 15 of 5:30Copy the code

PS: Beego’s timing module is relatively powerful, supporting timing tasks at the second level

Now, assuming the current time is 21:11:05, how do you define a scheduled task that runs in a loop every 5 minutes?

Online search, most of the solutions are like this:

0 */5 * * * *
Copy the code

Ok, let’s run the timed task and see what happens:

2019/10/05 21:11:05:087825 local[INFO] -- -- -- -- -- - timed tasks: [Test] load success -- -- -- -- -- - the cron. Go: 155 2019/10/05 21:12:00:007810local[DEBUG] Scheduled task: [Test] The Redis distributed lock is successfully obtained and the task delivery. Go :90 2019/10/05 21:12:036411local[DEBUG] Scheduled task: [Test] Scheduling succeeds... . 2019/10/05 21:17:00:004286local[DEBUG] Scheduled task: [Test] The Redis distributed lock is successfully obtained and the scheduling task delivery. Go :90 2019/10/05 21:17:00:010506local[DEBUG] Scheduled task: [Test] Scheduling succeeds... .Copy the code

Strange, why the task is not running at 21:16:05, but at 21:12:00

The general explanation on the Internet is:

If N is divisible by 60, it will be executed every N minutes, which is exactly 60/N times per hour. If N is not divisible by 60, it is executed when it is divisible and when the remainder of division is 0.

How to solve it?

  • seconds

    Second (first digit) : Replace the current second /60, and run every 60 seconds after the current second.

  • Sub (replace only those of the following format):

    * /?

    Minute (second) : replace with the current minute/every minute, every minute after the current minute;

  • Hour (replace only the following format):

    * /?

    Hour (third bit) : Replace the current hour with the number of hours every, and the number of hours after the current hour.

For example:Every seven minutes,Every 9 minutes,Every 14 minutes,Every 27 minutes

21:16:05, for example

0, 7 * * * * * / replace with: 5/60-16/7 * * * * 0 9 * * * * * / replace with: 5/60-16/9 * * * * 0 14 * * * * * / replace with: 5/60 16/14 * * * * 0 27 * * * * * / replace with: 5/60 16/27 * * * *Copy the code
Code solution:
func ConvertSecond(spec string) string {
	ifspec ! ="" {
		_spec := strings.Split(spec, "")
		hour, minute, second := time.Now().Clock()

		/ / the second processing
		_second := strconv.FormatInt(int64(second), 10) + 60 "/"
		spec = strings.Replace(spec, _spec[0], _second, 1)

		// minute (similar to: */5)
		if strings.HasPrefix(_spec[1]."* /") {
			_minute := strconv.FormatInt(int64(minute), 10) + "/" + strings.Trim(_spec[1]."* /")
			spec = strings.Replace(spec, _spec[1], _minute, 1)}// hour processing (similar to: */5)
		if strings.HasPrefix(_spec[2]."* /") {
			_hour := strconv.FormatInt(int64(hour), 10) + "/" + strings.Trim(_spec[2]."* /")
			spec = strings.Replace(spec, _spec[2], _hour, 1)}return spec
	}

	return ""
}
Copy the code

Ok, let’s run the scheduled task again and check the result:

2019/10/05 21:18:38:333458  local[INFO] -- -- -- -- -- - timed tasks: [Test] load success -- -- -- -- -- - the cron. Go: 155 2019/10/05 21:23:38:002390local[DEBUG] Scheduled task: [Test] The Redis distributed lock is successfully obtained and the scheduling task delivery. Go :90 2019/10/05 21:23:38:009905local[DEBUG] Scheduled task: [Test] Scheduling succeeds... . 2019/10/05 21:28:38:008273local[DEBUG] Scheduled task: [Test] The Redis distributed lock is successfully obtained and the scheduling task delivery. Go :90 2019/10/05 21:28:38:011781local[DEBUG] Scheduled task: [Test] Scheduling succeeds... .Copy the code

In line with expectations