goCron: A Golang Job Scheduling Package.

Note from current maintainers:

A currently maintained fork of this project has been migrated to https://github.com/go-co-op/gocron

Disclaimer: we (the maintainers) tried, with no luck, to get in contact with Jason (the repository owner) in order to add new maintainers or leave the project within an organization. Unfortunately, he hasn't replied for months now (March, 2020).

So, we decided to move the project to a new repository (as stated above), in order to keep the evolution of the project coming from as many people as possible. Feel free to reach over!

goCron: A Golang Job Scheduling Package.

This package is currently looking for new maintainers (cause @jasonlvhit is in ICU). Please message @jasonlvhit if you are interested.

GgoDoc Go Report Card

goCron is a Golang job scheduling package which lets you run Go functions periodically at pre-determined interval using a simple, human-friendly syntax.

goCron is a Golang implementation of Ruby module clockwork and Python job scheduling package schedule, and personally, this package is my first Golang program, just for fun and practice.

See also this two great articles:

If you want to chat, you can find us at Slack!

Back to this package, you could just use this simple API as below, to run a cron scheduler.

package main

import (
	"fmt"
	"time"

	"github.com/jasonlvhit/gocron"
)

func task() {
	fmt.Println("I am running task.")
}

func taskWithParams(a int, b string) {
	fmt.Println(a, b)
}

func main() {
	// Do jobs without params
	gocron.Every(1).Second().Do(task)
	gocron.Every(2).Seconds().Do(task)
	gocron.Every(1).Minute().Do(task)
	gocron.Every(2).Minutes().Do(task)
	gocron.Every(1).Hour().Do(task)
	gocron.Every(2).Hours().Do(task)
	gocron.Every(1).Day().Do(task)
	gocron.Every(2).Days().Do(task)
	gocron.Every(1).Week().Do(task)
	gocron.Every(2).Weeks().Do(task)

	// Do jobs with params
	gocron.Every(1).Second().Do(taskWithParams, 1, "hello")

	// Do jobs on specific weekday
	gocron.Every(1).Monday().Do(task)
	gocron.Every(1).Thursday().Do(task)

	// Do a job at a specific time - 'hour:min:sec' - seconds optional
	gocron.Every(1).Day().At("10:30").Do(task)
	gocron.Every(1).Monday().At("18:30").Do(task)
	gocron.Every(1).Tuesday().At("18:30:59").Do(task)

	// Begin job immediately upon start
	gocron.Every(1).Hour().From(gocron.NextTick()).Do(task)

	// Begin job at a specific date/time
	t := time.Date(2019, time.November, 10, 15, 0, 0, 0, time.Local)
	gocron.Every(1).Hour().From(&t).Do(task)

	// NextRun gets the next running time
	_, time := gocron.NextRun()
	fmt.Println(time)

	// Remove a specific job
	gocron.Remove(task)

	// Clear all scheduled jobs
	gocron.Clear()

	// Start all the pending jobs
	<- gocron.Start()

	// also, you can create a new scheduler
	// to run two schedulers concurrently
	s := gocron.NewScheduler()
	s.Every(3).Seconds().Do(task)
	<- s.Start()
}

and full test cases and document will be coming soon (help is wanted! If you want to contribute, pull requests are welcome).

If you need to prevent a job from running at the same time from multiple cron instances (like running a cron app from multiple servers), you can provide a Locker implementation and lock the required jobs.

gocron.SetLocker(lockerImplementation)
gocron.Every(1).Hour().Lock().Do(task)

Once again, thanks to the great works of Ruby clockwork and Python schedule package. BSD license is used, see the file License for detail.

Looking to contribute? Try to follow these guidelines:

  • Use issues for everything
  • For a small change, just send a PR!
  • For bigger changes, please open an issue for discussion before sending a PR.
  • PRs should have: tests, documentation and examples (if it makes sense)
  • You can also contribute by:
    • Reporting issues
    • Suggesting new features or enhancements
    • Improving/fixing documentation

Have fun!

Comments
  • Interval doesn't work correctly

    Interval doesn't work correctly

    I try to run a task every 3 seconds, but it still runs every second:

    func Hello() {
    	fmt.Printf("hello %d\n", time.Now().Unix())
    }
    
    func main() {
    	gocron.Every(3).Seconds().Do(Hello)
    	<-gocron.Start()
    }
    

    The result is:

    hello 1561223112
    hello 1561223113
    hello 1561223114
    hello 1561223115
    hello 1561223116
    hello 1561223117
    hello 1561223118
    
  • Adds production ready safety

    Adds production ready safety

    This PR was requested to be opened. It is a series of changes that make the code more production safe. In general it's not good practice to panic in source code that is meant to be imported. The user should be able to "catch" based on errors and not have to rely on defer recover

  • Jobs start at different time

    Jobs start at different time

    Hey, I'll try and explain this as best as possible.

    Say I set a task at 09:30

    scheduler := gocron.NewScheduler() scheduler.Every(1).Day().At("09:30").Do(someTask)

    Say my task takes 10 minutes to complete at 09:30 and ends at 09:40, the next day, the task starts at 9:40, and repeats this, so eventually this task will be running at a completely different time if left forever.

    Not sure if you've noticed this, but i thought it would be worth mentioning.

    Thanks!

  • Day of the Week not working?

    Day of the Week not working?

    I have written a simple program that writes hello at a certain time on both Monday and Friday:

    package main
    import (
      "fmt"
      "github.com/jasonlvhit/gocron"
    )
    
    func main() {
      gocron.Every(1).Monday().At("15:54").Do(func() { fmt.Println("Hi from Monday!") })
      gocron.Every(1).Friday().At("15:54").Do(func() { fmt.Println("Hi from Friday!") })
      <-gocron.Start()
    }
    
    

    The output today (Friday) at 15:54 on my OS X machine was this:

    Hi from Monday!
    Hi from Friday!
    

    Also, it is not relevant that the two times were the same. This

      gocron.Every(1).Monday().At("16:13").Do(func() { fmt.Println("Hi from Friday!") })
      gocron.Every(1).Friday().At("16:14").Do(func() { fmt.Println("Hi from Monday!") })
    

    produced this by 16:14:

    Hi from Friday!
    Hi from Monday!
    

    Any ideas?

  • Run task just once

    Run task just once

    Is there a idiomatic way of scheduling a task to run just once? That is to say, create a schedule that is ran once and then cleared?

    The only way I can think of is:

    func scheduleOnce() {
      s := gocron.NewScheduler()
      s.Every(1).Day().At("10:30").Do(foo, s)
      <- s.Start()
    }
    
    func foo(s *gocron.Scheduler) {
      // My code
      s.Clear()
    }
    

    Which I haven't actually tested yet but I figured this would be a solution to my problem.

  • DoSafely() doesn't actually do anything

    DoSafely() doesn't actually do anything

    When running a task with DoSafely, it never actually performs the task.

    Here is an example main.go file:

    package main
    
    import (
    	"io/ioutil"
    	"log"
    
    	"github.com/jasonlvhit/gocron"
    )
    
    func task() {
    	log.Println("I am runnning task.")
    	d1 := []byte("hello\ngo\n")
    	ioutil.WriteFile("/tmp/dat1", d1, 0644)
    }
    
    func main() {
    	s := gocron.NewScheduler()
    	s.Every(3).Seconds().DoSafely(task)
    	<-s.Start()
    }
    

    Test it out - if you swap in Do for DoSafely it works as expected, outputs to the terminal and writes the file. With DoSafely nothing happens.

  • add func BeginNow to start job immediately

    add func BeginNow to start job immediately

    • Adds the BeginNow function and a test (thoughts on the func name? words are hard...)
      • Usage looks like gocron.Every(1).Hour().BeginNow().Do(task)
      • resolves https://github.com/jasonlvhit/gocron/issues/115
    • sets const values for seconds, minutes, etc.
    • Address golint requirement for exported functions to have comments in the form of funcName ... description
  • The package is full of race conditions + panics

    The package is full of race conditions + panics

    If you run your test with the race flag on go test ./... -race -v go will flag the package with having race conditions.

    Also, panics are dangerous in production. I've forked and created a production safe version

    https://github.com/marcsantiago/gocron

  • At() seems to be not working

    At() seems to be not working

    gocron.Every(1).Day().At("9:00").Do(task)

    The task gets run every day at time of scheduling execution instead of every day at specified timing

  • Scheduled job gets delayed by the running time of the job in a long running (daemon like) program

    Scheduled job gets delayed by the running time of the job in a long running (daemon like) program

    I have written a little tool to backup my database every day at 0:00 and 13:00, thus:

    gocron.Every(1).Day().At("00:00").Do(mainRoutine)
    gocron.Every(1).Day().At("13:00").Do(mainRoutine)
    <-gocron.Start()
    

    The backup action itself takes around 10~12 seconds. I have set up a logger inside the program, and these are the log output:

    INFO[2016-02-19 15:26:29.008 +0800] Backup program is starting.
    INFO[2016-02-19 15:26:29.008 +0800] Scheduled backup job on 00:00
    INFO[2016-02-19 15:26:29.008 +0800] Scheduled backup job on 13:00
    INFO[2016-02-20 00:00:00.016 +0800] Below are databases owned by maddie, they will be backed up:
    INFO[2016-02-20 00:00:00.016 +0800] db
    INFO[2016-02-20 00:00:10.399 +0800] Database db is backed up as /home/db/database-backups/2016/02/db-20160220-00.bak.
    INFO[2016-02-20 00:00:10.399 +0800] Backup finished.
    INFO[2016-02-20 13:00:00.016 +0800] Below are databases owned by maddie, they will be backed up:
    INFO[2016-02-20 13:00:00.017 +0800] db
    INFO[2016-02-20 13:00:11.872 +0800] Database db is backed up as /home/db/database-backups/2016/02/db-20160220-13.bak.
    INFO[2016-02-20 13:00:11.873 +0800] Backup finished.
    INFO[2016-02-21 00:00:11.016 +0800] Below are databases owned by maddie, they will be backed up:
    INFO[2016-02-21 00:00:11.016 +0800] db
    INFO[2016-02-21 00:00:22.338 +0800] Database db is backed up as /home/db/database-backups/2016/02/db-20160221-00.bak.
    INFO[2016-02-21 00:00:22.338 +0800] Backup finished.
    INFO[2016-02-21 13:00:12.016 +0800] Below are databases owned by maddie, they will be backed up:
    INFO[2016-02-21 13:00:12.016 +0800] db
    INFO[2016-02-21 13:00:22.767 +0800] Database db is backed up as /home/db/database-backups/2016/02/db-20160221-13.bak.
    INFO[2016-02-21 13:00:22.767 +0800] Backup finished.
    INFO[2016-02-22 00:00:23.017 +0800] Below are databases owned by maddie, they will be backed up:
    INFO[2016-02-22 00:00:23.017 +0800] db
    INFO[2016-02-22 00:00:32.908 +0800] Database db is backed up as /home/db/database-backups/2016/02/db-20160222-00.bak.
    INFO[2016-02-22 00:00:32.908 +0800] Backup finished.
    INFO[2016-02-22 13:00:23.016 +0800] Below are databases owned by maddie, they will be backed up:
    INFO[2016-02-22 13:00:23.016 +0800] db
    INFO[2016-02-22 13:00:34.653 +0800] Database db is backed up as /home/db/database-backups/2016/02/db-20160222-13.bak.
    INFO[2016-02-22 13:00:34.653 +0800] Backup finished.
    INFO[2016-02-23 00:00:33.018 +0800] Below are databases owned by maddie, they will be backed up:
    INFO[2016-02-23 00:00:33.018 +0800] db
    INFO[2016-02-23 00:00:43.447 +0800] Database db is backed up as /home/db/database-backups/2016/02/db-20160223-00.bak.
    INFO[2016-02-23 00:00:43.447 +0800] Backup finished.
    INFO[2016-02-23 13:00:35.016 +0800] Below are databases owned by maddie, they will be backed up:
    INFO[2016-02-23 13:00:35.016 +0800] db
    INFO[2016-02-23 13:00:46.023 +0800] Database db is backed up as /home/db/database-backups/2016/02/db-20160223-13.bak.
    INFO[2016-02-23 13:00:46.023 +0800] Backup finished.
    INFO[2016-02-24 00:00:44.016 +0800] Below are databases owned by maddie, they will be backed up:
    INFO[2016-02-24 00:00:44.016 +0800] db
    INFO[2016-02-24 00:00:53.945 +0800] Database db is backed up as /home/db/database-backups/2016/02/db-20160224-00.bak.
    INFO[2016-02-24 00:00:53.945 +0800] Backup finished.
    INFO[2016-02-24 13:00:47.016 +0800] Below are databases owned by maddie, they will be backed up:
    INFO[2016-02-24 13:00:47.016 +0800] db
    INFO[2016-02-24 13:00:58.153 +0800] Database db is backed up as /home/db/database-backups/2016/02/db-20160224-13.bak.
    INFO[2016-02-24 13:00:58.153 +0800] Backup finished.
    INFO[2016-02-25 00:00:54.016 +0800] Below are databases owned by maddie, they will be backed up:
    INFO[2016-02-25 00:00:54.016 +0800] db
    INFO[2016-02-25 00:01:05.071 +0800] Database db is backed up as /home/db/database-backups/2016/02/db-20160225-00.bak.
    INFO[2016-02-25 00:01:05.071 +0800] Backup finished.
    INFO[2016-02-25 13:00:59.016 +0800] Below are databases owned by maddie, they will be backed up:
    INFO[2016-02-25 13:00:59.016 +0800] db
    INFO[2016-02-25 13:01:10.720 +0800] Database db is backed up as /home/db/database-backups/2016/02/db-20160225-13.bak.
    INFO[2016-02-25 13:01:10.720 +0800] Backup finished.
    

    As you can see, after each scheduled job being executed, the next job will be delayed by 10~12 seconds which is the execution time of the backup routine.

    Is this by design? If yes, is there a way to change the behaviour?

  • Can I schedule a task to repeat only on weekdays?

    Can I schedule a task to repeat only on weekdays?

    gocron.Every(1).Weekday(1).At("12:00").Do(func() {
    	SendMessage(api, *channelID, "2")
    })
    

    Above code does not work. I want schedule jobs on weekday. except weekend.

    Monday, Tuesday, ... It seems very inefficient to write every single day of the week code.

  • .Do overrides existing cron tasks

    .Do overrides existing cron tasks

    I ran into a really nasty issue with StartImmediately and .Do(). Basically the following code will behave completely un-expected:

    func main() {
    	scheduler := gocron.NewScheduler(time.UTC)
    	scheduler.Every(15 * time.Second).Do(func() {
    		log.Printf("normal cron at: %v", time.Now())
    	})
    	scheduler.StartAsync()
    
    	timer := time.NewTimer(5 * time.Second)
    	<-timer.C
    	scheduler.StartImmediately().Do(func() {
    		log.Printf("Something completely different")
    	})
    
    	blockUntilTermSignal()
    }
    

    The output is:

    2021/11/29 13:34:10 normal cron at: 2021-11-29 13:34:10.541174 +0100 CET m=+0.001237376
    2021/11/29 13:34:25 Something completely different
    2021/11/29 13:34:30 Something completely different
    

    So until the subsequent/unqualified .Do() call the scheduler will run the "normal" 15 second func, but once a .Do is set it replaces the existing one with the newly passed func.

    The (for me) expected output should have been:

    2021/11/29 13:35:10 normal cron at: 2021-11-29 13:35:10.215062 +0100 CET m=+0.000477251
    2021/11/29 13:35:15 Something completely different
    2021/11/29 13:35:25 normal cron at: 2021-11-29 13:35:25.220175 +0100 CET m=+15.005519585
    

    To get to this I had to change the code to:

            scheduler.Every(1).Millisecond().LimitRunsTo(1).Do(func() {
    		log.Printf("Something completely different")
    	})
    

    I can understand that this is probably a mistake on my part or that I am mis-using the libs fluent interface - but then again this code looks totally normal and when reading this I'd expect to be scheduling 2 separate jobs - not to replace the existing payload :/

    Maybe some safeguards can be inserted into Do to prevent it from overriding the previous already submitted func?

  • How to make stop Scheduler?

    How to make stop Scheduler?

    Dear Contributors,

    I've tested gocron to understand its behavior. I've got obtained a result that I cannot understand. I reckon that "gocron" Scheduler will be stopped if I assign a value to the channel that obtained from Start() function's return value. But, jobs still running even if "Scheduler Finished" is executed.

    What do I have to do to stop the Scheduler?

    func stuff() {
        defer func() {
            fmt.Printf("doing the job: 1\n")
        }()
    }
    
    func jobs(quit <-chan bool) {
        g := gocron.NewScheduler()
        g.Every(1).Second().Do(stuff)
        stopped := g.Start()
    
        for {
            select {
                case <-quit:
                    stopped <- true
                case <-stopped:
                    fmt.Println("Scheduler Finished")
                    return
            }
        }
    }
    
    func TestGoCron(t *testing.T) {
        q := make(chan bool)
        go jobs(q)
    
        time.Sleep(5 * time.Second)
    
        q <- true
    
        time.Sleep(5 * time.Second)
        close(q)
        fmt.Println("main")
    }
    

    ----------------------- Result ----------------------- doing the job: 1 doing the job: 1 doing the job: 1 doing the job: 1 Scheduler Finished doing the job: 1 doing the job: 1 doing the job: 1 doing the job: 1 doing the job: 1 doing the job: 1 main

  • About task execution time

    About task execution time

    My task is set to execute time, but it does not take effect。 I want to execute once every minute, at 00 seconds 。So I used this method。 At。But the exection is 56 seconds。

    For example, gocron.Every(1).Minute().At("00:00:00").Do(db.task) but run time is I0611 15:40:55.602110 image

  • exec time

    exec time

    I want set last day of every month to exec command.
    I use "0 0 8 28-31 * * " ,but not what I wanted Would you please tell me what I should do?

  • Async Scheduler

    Async Scheduler

    Every 3 seconds call function process but sometimes has delay to response, accumulating the time..

    How call async function every 3 seconds?

    s := gocron.NewScheduler()
    s.Every(3).Seconds().Do(task)
    <- s.Start()
    
Related tags
clockwork - Simple and intuitive job scheduling library in Go.
clockwork - Simple and intuitive job scheduling library in Go.

clockwork A simple and intuitive scheduling library in Go. Inspired by python's schedule and ruby's clockwork libraries. Example use package main imp

Jul 27, 2022
Job scheduling made easy.

scheduler Job scheduling made easy. Scheduler allows you to schedule recurrent jobs with an easy-to-read syntax. Inspired by the article Rethinking Cr

Dec 30, 2022
A zero-dependencies and lightweight go library for job scheduling

A zero-dependencies and lightweight go library for job scheduling.

Aug 3, 2022
A lightweight job scheduler based on priority queue with timeout, retry, replica, context cancellation and easy semantics for job chaining. Build for golang web apps.

Table of Contents Introduction What is RIO? Concern An asynchronous job processor Easy management of these goroutines and chaining them Introduction W

Dec 9, 2022
Executes jobs in separate GO routines. Provides Timeout, StartTime controls. Provides Cancel all running job before new job is run.

jobExecutor Library to execute jobs in GO routines. Provides for Job Timeout/Deadline (MaxDuration()) Job Start WallClock control (When()) Add a job b

Jan 10, 2022
Scheduler - Scheduler package is a zero-dependency scheduling library for Go

Scheduler Scheduler package is a zero-dependency scheduling library for Go Insta

Jan 14, 2022
Simple, zero-dependency scheduling library for Go

go-quartz Simple, zero-dependency scheduling library for Go. About Inspired by the Quartz Java scheduler. Library building blocks Job interface. Any t

Dec 30, 2022
Easy and fluent Go cron scheduling

goCron: A Golang Job Scheduling Package. goCron is a Golang job scheduling package which lets you run Go functions periodically at pre-determined inte

Jan 8, 2023
Distributed Task Scheduling System|分布式定时任务调度平台
Distributed Task Scheduling System|分布式定时任务调度平台

Crocodile Distributed Task Scheduling System English | 中文 Introduction A distributed task scheduling system based on Golang that supports http request

Jan 5, 2023
nano-gpu-scheduler is a Kubernetes scheduler extender for GPU resources scheduling.
nano-gpu-scheduler is a Kubernetes scheduler extender for GPU resources scheduling.

Nano GPU Scheduler About This Project With the continuous evolution of cloud native AI scenarios, more and more users run AI tasks on Kubernetes, whic

Dec 29, 2022
K8s cluster simulator for workload scheduling.
K8s cluster simulator for workload scheduling.

Open-Simulator Motivation 概念定义 Open-Simulator 是 K8s 下的仿真调度组件。用户准备一批待创建 Workload 资源,Workload 资源指定好资源配额、绑核规则、亲和性规则、优先级等,通过 Open-Simulator 的仿真调度能力可判断当前集群

Dec 25, 2022
A way of scheduling volcano jobs

JobFlow 背景 volcano Volcano是CNCF 下首个也是唯一的基于Kubernetes的容器批量计算平台,主要用于高性能计算场景。 它提供了Kubernetes目前缺 少的一套机制,这些机制通常是机器学习大数据应用、科学计算、 特效渲染等多种高性能工作负载所需的。 现状:当前vol

Oct 12, 2022
golang job dispatcher
golang job dispatcher

go-gearman The shardingkey is hashed to the same queue, each of which is bound to a worker.

Dec 28, 2022
goInterLock is golang job/task scheduler with distributed locking mechanism (by Using Redis🔒).
goInterLock is golang job/task scheduler with distributed locking mechanism (by Using Redis🔒).

goInterLock is golang job/task scheduler with distributed locking mechanism. In distributed system locking is preventing task been executed in every instant that has the scheduler,

Dec 5, 2022
a self terminating concurrent job queue for indeterminate workloads in golang

jobtracker - a self terminating concurrent job queue for indeterminate workloads in golang This library is primarily useful for technically-recursive

Sep 6, 2022
You had one job, or more then one, which can be done in steps

Leprechaun Leprechaun is tool where you can schedule your recurring tasks to be performed over and over. In Leprechaun tasks are recipes, lets observe

Nov 23, 2022
A programmable, observable and distributed job orchestration system.
A programmable, observable and distributed job orchestration system.

?? Overview Odin is a programmable, observable and distributed job orchestration system which allows for the scheduling, management and unattended bac

Dec 21, 2022
Machinery is an asynchronous task queue/job queue based on distributed message passing.
Machinery is an asynchronous task queue/job queue based on distributed message passing.

Machinery Machinery is an asynchronous task queue/job queue based on distributed message passing. V2 Experiment First Steps Configuration Lock Broker

Dec 24, 2022
Run Jobs on a schedule, supports fixed interval, timely, and cron-expression timers; Instrument your processes and expose metrics for each job.

A simple process manager that allows you to specify a Schedule that execute a Job based on a Timer. Schedule manage the state of this job allowing you to start/stop/restart in concurrent safe way. Schedule also instrument this Job and gather metrics and optionally expose them via uber-go/tally scope.

Dec 8, 2022