Task Scheduling
Schedule tasks with concurrency and time package. Scheduling has this benefits:
- Run processes at off-peak hours to use resources efficiently.
- Create backups, updates, and maintenance.
- In distributed systems, manage when and how tasks are executed in parallel.
- Make sure tasks are performed at regular intervals.
Create a scheduler
Define a Job type and a Scheduler type:
Jobtakes no arguments and returns no value.Schedulerhas a channel namedjobQueuethat stores and manages scheduled jobs.- The factory function creates a new scheduler. It creates a buffered channel of a given size so you can add jobs to
jobQueuewithout blocking.
type Job func() // 1
type Scheduler struct { // 2
jobQueue chan Job
}
func NewScheduler(size int) *Scheduler { // 3
return &Scheduler{
jobQueue: make(chan Job, size),
}
}
Next, define the behavior of the scheduler. We want to run every job in its own goroutine:
- The
Startmethod ranges through all jobs injobQueueand runs each in a goroutine. Schedulesends a job in tojobQueue.- Because this happens in a goroutine,
Scheduledoesn’t block execution for the duration of delay.
func (s *Scheduler) Start() { // 1
for job := range s.jobQueue {
go job()
}
}
func (s *Scheduler) Schedule(job Job, delay time.Duration) { // 2
go func() { // 3
time.Sleep(delay)
s.jobQueue <- job
}()
}
Here is how you run the scheduler:
- Create the new sheduler. This scheduler can run 10 concurrent jobs.
- Define the
Schedulemethod for the scheduler. This example uses an anonymous function that prints a message to the console after 5 seconds. - Start the scheduler.
fmt.Scanln()reads input from stdin. For this program, it reads Enter from the keyboard.
func main() {
scheduler := NewScheduler(10) // 1
scheduler.Schedule(func() { // 2
fmt.Println("Job executed at", time.Now())
}, 5*time.Second)
go scheduler.Start() // 3
fmt.Println("Sheduler started. Press 'Enter' to exit.") // 4
fmt.Scanln() // 5
}
Timer signals
A Ticker lets you do something at regular intervals. You can combine this with a scheduler to execute a task at regular intervals. This example runs a task every second for 10 seconds:
- Create a
Ticker. A ticker has a send channel of typeTimethat accepts ticks from the ticker. This is how you define the interval between tasks. - Ensure the ticker turns off.
- Create a
Timer. This is the period of time that the scheduler runs. This timer runs for 10 seconds. - Ensure the timer turns off.
- Use an infinte
forloop andselectstatement to wait for events. - When
tickreceives a value from the ticker, it prints a message to the console. - When a value is returned on
timer, it prints a message and returns, ending the program.
func main() {
ticker := time.NewTicker(1 * time.Second) // 1
defer ticker.Stop() // 2
timer := time.NewTimer(10 * time.Second) // 3
defer timer.Stop() // 4
for { // 5
select {
case tick := <-ticker.C: // 6
fmt.Println("Tick at", tick)
case <-timer.C: // 7
fmt.Println("Timer expired")
return
}
}
}