“This is the fifth day of my participation in the November Gwen Challenge. See details of the event: The Last Gwen Challenge 2021”.

Golang Scheduled task

1 Installation Dependencies

Go get github.com/robfig/cron/[email protected]Copy the code

2 Scheduled task HelloWorld

package main

import (
	"fmt"
	"github.com/robfig/cron/v3"
	"time"
)

func main(a) {
	// Create a scheduled task object
	Cron can be accurate to the second, and most expression formats start from the second.
	//crontab := cron.new () Schedules time from minutes by default
	crontab := cron.New(cron.WithSeconds()) // Accurate to the second
	// Define the task function called by timer
	task := func(a) {
		fmt.Println("hello world", time.Now())
	}
	// Scheduled task
	spec := "*/5 * * * *?" // Cron expression, every five seconds
	// Add a scheduled task,
	crontab.AddFunc(spec, task)
	// Start timer
	crontab.Start()
	// The scheduled task is executed separately from the coroutine, where the select short block is used. Required in actual development
	// Control according to the actual situation
	select {} // The blocking main thread stops} -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the output -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- hello world2020- 0318 11:13:00.0241639 +0800 CST m=+3.113746301
hello world 2020- 0318 11:13:05.0007375 +0800 CST m=+8.090319901
hello world 2020- 0318 11:13:10.0004232 +0800 CST m=+13.090005601
hello world 2020- 0318 11:13:15.0003857 +0800 CST m=+18.089968101
hello world 2020- 0318 11:13:20.0003788 +0800 CST m=+23.089961201
Copy the code

3 Cron expression

Cron expressions are a nice thing to use not only in Java’s quartZ, but also in the Go language. I haven’t used cron on Linux, but it is also possible to use crontab -e to configure scheduled tasks on Linux. It is accurate to the second in Go and Java, but not in Linux. The CRON expression represents a collection of times, represented by six space-separated fields:

The field name Whether must Allowed values A specific character that is allowed
Seconds (Seconds) is 0-59 – * /
Points (Minute) is 0-59 – * /
(Hours) is 0-23 – * /
Day (Day of the month) is 1-31 * /, -?
Month (Month) is 1-12 or JAN – DEC – * /
Day of Week no 0 to 6 or SUM – SAT * /, -?

3.1 Expression description of Corn

  • The values of the Month and Day of week fields are case insensitive, for example, SUN, SUN, and SUN are the same.
  • The Day of week field is equivalent to * if not provided

3.2 Example description of Corn expressions

If we use crontab := cron.new (cron.withseconds ()), for example if we pass a string that is: “* * * * * *” in the first argument to crontab.addfunc (), what are the six * s? If you use crontab := cron.new (), you only need five *, such as * * * * *

┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ the second range (0 - 60) │ viewpoint of chrysene ── min (0 - 59) │ ├ ─ chrysene ── hour (0 - 23) │ │ chrysene ─── day of month (1 - 31) │ │ chrysene ─── month (1 - 12() │ │ chrysene ─── day of week (0 - 6) (0 to 6Are Sunday to │ │ │ │ │ │ Saturday) │ │ │ │ │ │ │ │ │ │ │ │ * * * * * *Copy the code

3.3 Description of CrON Characters

symbol instructions
(*) Indicates that the CRon expression matches all values of the field. For example, the asterisk (month) in the fifth field indicates every month
(/) Indicates the growth interval. For example, if the value of the first field (minutes) is 3-59/15, it indicates that the execution starts at the third minute of every hour and then every 15 minutes (at 3, 18, 33, and 48), which can also be expressed as 3/15
(,) Used to enumerate values, such as MON,WED,FRI, which are executed on Monday, Wednesday, and Friday
(-) Denotes a range, such as the value of the third field 9-17 denotes 9am to 5pm directly per hour (including 9 and 17)
(?) It is used only for Day of month and week, indicating that no value is specified. It can be used instead of *

3.4 Common CrON Examples

every5Run the command once every second: */5* * * *? every1Run this command once every minute:0* /1* * *? Every day,23Click execute once:0 0 23* *? In the morning every day1Click execute once:0 0 1* *? A month1No. In the morning1Click execute once:0 0 1 1*? Every Monday and Wednesday night22:30: 00 30 22 * * 1.326Points,29Points,33Execute each time:0 26.29.33* * *? Every day,0The point,13The point,18The point,21All points are executed once:0 0 0.13.18.21* *? Every Thursday afternoon in March14:10and14:40:  00 10.40 14 ? 3 4 
Copy the code

3.5 Predefined time format

You can use several predefined expressions to replace the expressions in the table above, using the following

The input describe equation
@yearly (or @annually) Run once a year at midnight on January 1 0, 0, 1, 1 star
@monthly Run once at midnight on the first day of the month 0, 0, 0, 1 * *
@weekly It runs once a week at midnight on Saturdays 0, 0, 0 * * 0
@daily (or @midnight) Run once a day at midnight 0, 0, 0 * * *
@hourly Run every hour 0 0 * * * *
@every <duration> every duration
c := cron.New() 
c.AddFunc("@every 1h30m".func(a) { fmt.Println("Every hour thirty")})Copy the code

4 Multiple scheduled tasks

package main

import (
	"fmt"
	"github.com/robfig/cron/v3"
	"time"
)

type TestTask struct {
	Name string
}

func (t *TestTask) Run(a) {
	fmt.Println("TestTask", t.Name)
}

type Test2Task struct {
	Name string
}

func (t *Test2Task) Run(a) {
	fmt.Println("Test2Task", t.Name)
}

func main(a) {
	// Create a scheduled task object
	Cron can be accurate to the second, and most expression formats start from the second.
	//crontab := cron.new () Schedules time from minutes by default
	crontab := cron.New(cron.WithSeconds()) // Accurate to the second
	// Define the task function called by timer
	// Scheduled task
	spec := "*/5 * * * *?" // Cron expression, every five seconds

	// Define the task function called by timer
	task := func(a) {
		fmt.Println("hello world", time.Now())
	}
	// Add a scheduled task
	crontab.AddFunc(spec, task)

	// Add multiple timers
	crontab.AddJob(spec, &TestTask{Name: "tom"})
	crontab.AddJob(spec, &Test2Task{Name: "jeck"})
	// Start timer
	crontab.Start()
	// Close scheduled tasks, but cannot close tasks that are already in execution.
	defer crontab.Stop()
	// The scheduled task is executed separately from the coroutine, where the select short block is used. Required in actual development
	// Control according to the actual situation
	select {} // The blocking main thread stops} -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the output -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- TestTask Tom Test2Task jeck hello world2020- 0318 13:22:10.0245997 +0800 CST m=+2.761856801
TestTask tom
Test2Task jeck
hello world 2020- 0318 13:22:15.0008245 +0800 CST m=+7.738081601.....................................................................Copy the code

5 Main types or interfaces

5.1 the Cron

Cron: contains a list of entities to execute; Support for pause [stop]; Add entities and so on

  • Note:
    • The Cron structure does not export any members.
    • One of the membersstopThe type isstruct{}, namely, empty structure.
type Cron struct {
    entries  []*Entry
    stop     chan struct{}   // Stop the Cron instance
    add      chan *Entry     // When Cron is already running, adding a new Entity is implemented through the add channel
    snapshot chan []*Entry   // Get snapshots of all entities
    running  bool            // True when already running; Otherwise it is false
}
Copy the code

5.2 Entry Schedules entities

type Entry struct {
    // The schedule on which this job should be run.
    // Schedules Job execution of the current Entity
    Schedule Schedule

    // The next time the job will run. This is the zero time if Cron has not been
    // started or this entry's schedule is unsatisfiable
    // Job Time of the next execution
    Next time.Time

    // The last time this job was run. This is the zero time if the job has never
    // been run.
    // Last execution time
    Prev time.Time

    // The Job to run.
    // Job to execute
    Job Job
}
Copy the code

5.3 the Job

Job: Each entity contains a Job to Run, which is an interface and has only one method: Run

type Job interface {
    Run()
}
Copy the code

Since the Job type is required in Entity, tasks that we want to run regularly need to implement the Job interface. Also, because the Job interface has only one method with no parameters and no return value, the author provides a type for ease of use

type FuncJob func(a)It implements the Job interface by simply implementing the Run() method:func (f FuncJob) Run(a)Thus, any function with no arguments and no return value can be used as a Job by casting it to FuncJob, as the AddFunc method does.Copy the code

5.4 the Schedule

Each entity contains a scheduler that schedules the execution of jobs. It is also an interface. A concrete implementation of Schedule is obtained by parsing Cron expressions. Two concrete implementations of Schedule are provided in the library, SpecSchedule and ConstantDelaySchedule.

type Schedule interface {
    // Return the next activation time, later than the given time.
    // Next is invoked initially, and then each time the job is run.
    // Returns the time when the Job of the same Entity is executed next time
    Next(time.Time) time.Time
}
Copy the code

5.4.1 SpecSchedule

From the Cron expressions introduced at the beginning, it’s easy to know what each field means, and parsing the various expressions will result in an instance of SpecSchedule. The Parse in the library returns an instance of SpecSchedule (which of course implements the Schedule interface)

type SpecSchedule struct {
    Second, Minute, Hour, Dom, Month, Dow uint64
}
Copy the code

5.4.2 ConstantDelaySchedule

type ConstantDelaySchedule struct {
    Delay time.Duration // The interval between loops
}
Copy the code

This is a simple loop scheduler, such as: every 5 minutes. Note that the minimum unit is seconds, not less than, say, milliseconds.

The Every function gets an instance of this type, resulting in a scheduler that executes Every 5 seconds. :

constDelaySchedule := Every(5e9)
Copy the code

6 Function Calls

6.1 Instantiating Cron

When instantiated, members use mostly default values;

func New(a) *Cron {
    return &Cron{
        entries:  nil,
        add:      make(chan *Entry),
        stop:     make(chan struct{}),
        snapshot: make(chan []*Entry),
        running:  false,}}Copy the code

6.2 Member Methods

If you still don’t understand each method call, you can take a look at the implementation source code for each function

// EntryID identifies an entry within a Cron instance
type EntryID int

// Add job to Cron
// As described above, this method simply casts CMD through the FuncJob type and then calls the AddJob method
func (c *Cron) AddFunc(spec string, cmd func(a)) (EntryID, error) 

// Add job to Cron
// The cron expression spec is parsed to the scheduler instance (Schedule) through the Parse function, and the c.schedule method is called
func (c *Cron) AddJob(spec string, cmd Job) (EntryID, error)

// Get a snapshot of all Entities of the current Cron
func (c *Cron) Entries(a)[] *Entry

// Location Gets the Location of the time zone
func (c *Cron) Location(a) *time.Location 

// Entry returns a snapshot of the given item, or nil if it cannot be found
func (c *Cron) Entry(id EntryID) Entry

// Delete entries to be run in the future.
func (c *Cron) Remove(id EntryID) 

// Instantiate an Entity with two parameters and add it to the current Cron
// Note: If the current Cron is not running, add the entity directly to the Cron;
// Otherwise, add the Entity to the running Cron via the add member channel
func (c *Cron) Schedule(schedule Schedule, cmd Job) EntryID

// Start a new Goroutine to run the current Cron
func (c *Cron) Start(a)

// Stop the current Cron by sending a struct{}{} to the stop member and setting running to false
// Stop tells Cron to stop, so send a value to channel, regardless of the value
// So the stop member is defined as an empty struct
func (c *Cron) Stop(a)

// Run the cron scheduler, if it is already running, do not run the op
func (c *Cron) Run(a)
Copy the code

7 More resources

The source address

The timer API