Task Scheduling
Latest update: December 6, 2022

Task Scheduling #

While there are several libraries out there that provide this, creating a simple task scheduler is a good exercise that anyone can use to up their skills with Go’s concurrency primitives and patterns.

Sample Implementation #

Here is a simple implementation of one such task scheduler. It is relatively straightforward and easy to copy over to any new project, without requiring the need for a separate dependency. Please, not that this implementation has not been tested for any possible edge case scenarios and has been provided for education and illustration purposes only. I would be happy to add your feedback, or improvements to it.

Go Playground Link

// scheduleTask executes the given task at regular intervals (specified by interval) until the given timeout is reached.
// If a task takes longer than one interval, the next one starts only after the previous task has finished.
func scheduleTask(task func() error, interval time.Duration, timeout time.Duration) {
	ctx, cancelFn := context.WithCancel(context.Background())
	defer cancelFn()
	go func() {
		loop(ctx, task, interval)
	}()
	time.Sleep(timeout)
	cancelFn()
}

func loop(ctx context.Context, task func() error, interval time.Duration) {
	newJob := make(chan struct{}, 1)
	ticker := time.NewTicker(interval)
	defer ticker.Stop()
	for {
		newJob <- struct{}{}
		go func() {
			defer func() {
				<-newJob
				if r := recover(); r != nil {
					log.Println("Recovered from a panicking job:", r)
				}
			}()
			log.Println("New job starting")
			task()
			log.Println("New job ending")
		}()
		select {
		case <-ticker.C:
		case <-ctx.Done():
			close(newJob)
			return
		}
	}
}

Using the function above becomes as simple as calling the function with the right interval and timeout, and passing an appropriate action to be executed:

func main() {
	var a = 0

	scheduleTask(func() error {
		time.Sleep(10 * time.Millisecond)
		// Simulate a random panic
		if a == 3 {
			a++
			panic("oops")
		}
		a++
		return nil
	}, time.Millisecond*100, time.Millisecond*1000)

	log.Println(a)
}

3rd-Party Libraries #

GitHub - go-co-op/gocron: Easy and fluent Go cron scheduling. This is a fork from https://github.com/jasonlvhit/gocron
Easy and fluent Go cron scheduling. This is a fork from https://github.com/jasonlvhit/gocron - GitHub - go-co-op/gocron: Easy and fluent Go cron scheduling. This is a fork from https://github.com/j...
GitHub - reugn/go-quartz: Minimalist and zero-dependency scheduling library for Go
Minimalist and zero-dependency scheduling library for Go - GitHub - reugn/go-quartz: Minimalist and zero-dependency scheduling library for Go