Chrono is a scheduler library that lets you run your task and code periodically

Overview

chrono

Go Report Card Build Status codecov

Chrono is a scheduler library that lets you run your tasks and code periodically. It provides different scheduling functionalities to make it easier to create a scheduling task.

Scheduling a One-Shot Task

The Schedule method helps us schedule the task to run once at the specified time. In the following example, the task will first be executed 1 second after the current time.  WithStartTime option is used to specify the execution time.

taskScheduler := chrono.NewDefaultTaskScheduler()

task, err := taskScheduler.Schedule(func(ctx context.Context) {
	log.Print("One-Shot Task")
}, WithStartTime(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second()+1))

if err == nil {
	log.Print("Task has been scheduled successfully.")
}

Scheduling a Task with Fixed Delay

Let's schedule a task to run with a fixed delay between the finish time of the last execution of the task and the start time of the next execution of the task. The fixed delay counts the delay after the completion of the last execution.

taskScheduler := chrono.NewDefaultTaskScheduler()

task, err := taskScheduler.ScheduleWithFixedDelay(func(ctx context.Context) {
	log.Print("Fixed Delay Task")
	time.Sleep(3 * time.Second)
}, 5 * time.Second)

if err == nil {
	log.Print("Task has been scheduled successfully.")
}

Since the task itself takes 3 seconds to complete and we have specified a delay of 5 seconds between the finish time of the last execution of the task and the start time of the next execution of the task, there will be a delay of 8 seconds between each execution.

WithStartTime and WithLocation options can be combined with this.

Schedule Task at a Fixed Rate

Let's schedule a task to run at a fixed rate of seconds.

taskScheduler := chrono.NewDefaultTaskScheduler()

task, err := taskScheduler.ScheduleAtFixedRate(func(ctx context.Context) {
	log.Print("Fixed Rate of 5 seconds")
}, 5 * time.Second)

if err == nil {
	log.Print("Task has been scheduled successfully.")
}

The next task will run always after 5 seconds no matter the status of the previous task, which may be still running. So even if the previous task isn't done, the next task will run. We can also use the WithStartTime option to specify the desired first execution time of the task.

now := time.Now()

task, err := taskScheduler.ScheduleAtFixedRate(func(ctx context.Context) {
	log.Print("Fixed Rate of 5 seconds")
}, 5 * time.Second, WithStartTime(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second() + 2))

When we use this option, the task will run at the specified execution time and subsequently with the given period. In the above example, the task will first be executed 2 seconds after the current time.

We can also combine this option with WithLocation based on our requirements.

now := time.Now()

task, err := taskScheduler.ScheduleAtFixedRate(func(ctx context.Context) {
	log.Print("Fixed Rate of 5 seconds")
}, 5 * time.Second, WithStartTime(now.Year(), now.Month(), now.Day(), 18, 45, 0),
WithLocation("America/New_York"))

In the above example, the task will first be executed at 18:45 of the current date in America/New York time. If the start time is in the past, the task will be executed immediately.

Scheduling a Task using Cron Expression

Sometimes Fixed Rate and Fixed Delay can not fulfill your needs, and we need the flexibility of cron expressions to schedule the execution of your tasks. With the help of the provided ScheduleWithCron method, we can schedule a task based on a cron expression.

taskScheduler := chrono.NewDefaultTaskScheduler()

task, err := taskScheduler.ScheduleWithCron(func(ctx context.Context) {
	log.Print("Scheduled Task With Cron")
}, "0 45 18 10 * *")

if err == nil {
	log.Print("Task has been scheduled")
}

In this case, we're scheduling a task to be executed at 18:45 on the 10th day of every month

By default, the local time is used for the cron expression. However, we can use the WithLocation option to change this.

task, err := taskScheduler.ScheduleWithCron(func(ctx context.Context) {
	log.Print("Scheduled Task With Cron")
}, "0 45 18 10 * *", WithLocation("America/New_York"))

In the above example, Task will be scheduled to be executed at 18:45 on the 10th day of every month in America/New York time.

WithStartTimeoption cannot be used with ScheduleWithCron.

Canceling a Scheduled Task

Schedule methods return an instance of type ScheduledTask, which allows us to cancel a task or to check if the task is canceled. The Cancel method cancels the scheduled task but running tasks won't be interrupted.

taskScheduler := chrono.NewDefaultTaskScheduler()

task, err := taskScheduler.ScheduleAtFixedRate(func(ctx context.Context) {
	log.Print("Fixed Rate of 5 seconds")
}, 5 * time.Second)

/* ... */
	
task.Cancel()

Shutting Down a Scheduler

The Shutdown() method doesn't cause immediate shut down of the Scheduler and returns a channel. It will make the Scheduler stop accepting new tasks and shut down after all running tasks finish their current work.

taskScheduler := chrono.NewDefaultTaskScheduler()

/* ... */

shutdownChannel := taskScheduler.Shutdown()
<- shutdownChannel
	
/* after all running task finished their works */

License

Chrono is released under MIT License.

Issues
  • *ATTENTION* `ScheduleWithCron` don't work as expected

    *ATTENTION* `ScheduleWithCron` don't work as expected

    The code I use:

    task, err = ts.ScheduleWithCron(func(ctx context.Context) {
    	fmt.Print("Scheduled Task With Cron\n")
    	ierrors.Println(logTag, "Scheduled Task With Cron\n")
    }, "* * * * * *", chrono.WithLocation("Etc/UTC"))
    

    I would expect that the cronjob here will run every second, but in real it runs every "tick"

    ....
    
    Scheduled Task With Cron
    2021-12-10T21:48:15.307977068Z (Fight): Scheduled Task With Cron
    
    Scheduled Task With Cron
    2021-12-10T21:48:15.308020282Z (Fight): Scheduled Task With Cron
    
    Scheduled Task With Cron
    2021-12-10T21:48:15.30807167Z (Fight): Scheduled Task With Cron
    
    Scheduled Task With Cron
    2021-12-10T21:48:15.308107834Z (Fight): Scheduled Task With Cron
    ....
    

    also its not working to use styles like:

    */5 * * * * *
    0 0-59/5 * * * * 
    0 */5 * * * * 
    0 1,6,11,16,21,26,31,36,41,46,51,56 * * * *
    ....
    

    this will result also in the run in "loop" or also like in while true loops.

    This will result in a very very bad DoS because the CPU load goes into the sky.

    bug invalid 
    opened by Dexus 8
  • `taskScheduler.Schedule` don't respect the `WithStartTime`

    `taskScheduler.Schedule` don't respect the `WithStartTime`

    I tested this Lib to create Timebased Jobs, from our MySQL Entries.

    But what I see is that each Job I put to the Schedule, is running right after i add it.

    task, err = ts.Schedule(func(ctx context.Context) {
    	ierrors.Println(logTag, "FightLoad Scheduled Task")
    	ierrors.Printf(logTag, "Time: %s\n", time.Now().UTC().String())
    	FightScript(fleet) // Print also the current Time same as the abdove
    }, chrono.WithStartTime(
    	fleet.Timein.Year(),
    	fleet.Timein.Month(),
    	fleet.Timein.Day(),
    	fleet.Timein.Hour(),
    	fleet.Timein.Minute(),
    	fleet.Timein.Second(),
    ), chrono.WithLocation(time.UTC.String()),
    )
    

    What I see is the Job is running right after the schedule, but the fleet.Timein is 10 minutes in the future.

    EDIT: If we remove chrono.WithLocation(time.UTC.String()) and use fleet.Timein.Local().*** it works as expected. Maybe this should be better documentated.

    bug 
    opened by Dexus 6
  • Tests not working correct

    Tests not working correct

    The tests, showing some problems:

    Running tool: /usr/local/go/bin/go test -timeout 1m30s -run ^TestCronExpression_NextTime$ **/chrono -v
    
    === RUN   TestCronExpression_NextTime
        **/chrono/cron_test.go:634: got: 2021-03-16 15:10:18 +0100 CET expected: 2021-03-16 15:04:17 +0000 UTC
        **/chrono/cron_test.go:634: got: 2021-03-16 15:10:21 +0100 CET expected: 2021-03-16 15:04:20 +0000 UTC
        **/chrono/cron_test.go:634: got: 2021-03-16 15:10:24 +0100 CET expected: 2021-03-16 15:04:23 +0000 UTC
        **/chrono/cron_test.go:634: got: 2021-03-16 15:10:27 +0100 CET expected: 2021-03-16 15:04:26 +0000 UTC
        **/chrono/cron_test.go:634: got: 2021-03-16 15:10:30 +0100 CET expected: 2021-03-16 15:04:29 +0000 UTC
        **/chrono/cron_test.go:634: got: 2021-03-16 15:10:33 +0100 CET expected: 2021-03-16 15:04:32 +0000 UTC
    --- FAIL: TestCronExpression_NextTime (0.00s)
    FAIL
    FAIL	github.com/Dexus-Forks/chrono	0.005s
    
    
    bug invalid 
    opened by Dexus 6
  • Add immediate mode

    Add immediate mode

    At startup.

    • For unit tests, I want tasks to run immediately and with no delay, even if there is a delay specified.
    • For production, I want tasks to run after a specified delay.

    What I see now is that tasks run immediately, regardless of what the delay is. They then run again after the delay.

    question proposal 
    opened by lookfirst 6
  • Does the scheduler persist?

    Does the scheduler persist?

    I am looking for a task scheduler which can execute tasks in the future. And Chrono seems pretty amazing! and close to my need.

    However, I'd like to know if there is a backing store? And does the schedule tasks persist through restarts as well?

    Thanks

    question 
    opened by prakashraman 2
  • Executor and Scheduler methods

    Executor and Scheduler methods

    Executor and Scheduler both share similar methods, for example :

    Executor

    Schedule(task Task, delay time.Duration) (ScheduledTask, error)	
    ScheduleWithFixedDelay(task Task, initialDelay time.Duration, delay time.Duration) (ScheduledTask, error)
    ScheduleAtFixedRate(task Task, initialDelay time.Duration, period time.Duration) (ScheduledTask, error)
    

    and

    Scheduler

    Schedule(task Task, options ...Option) (ScheduledTask, error)	
    ScheduleWithFixedDelay(task Task, delay time.Duration, options ...Option) (ScheduledTask, error)	
    ScheduleAtFixedRate(task Task, period time.Duration, options ...Option) (ScheduledTask, error)
    

    Don't you think this could be confusing considering that both interfaces are exported in the same package?

    opened by charconstpointer 2
  • Shutdown one-shot scheduler

    Shutdown one-shot scheduler

    I am currently using the one-shot scheduler to end an event. I want to shutdown that scheduler after the event is ended. However, I don't know where to put the shutdown code. The event ending scheduler look like this:

    	repo.endScheduler = chrono.NewDefaultTaskScheduler()
    	endTime := time.Unix(event.EndTime, 0)
    	if _, err := repo.endScheduler.Schedule(func(ctx context.Context) {
    		err := repo.end(event.ID)
    		if err != nil {
    			log.Fatalf("Failed to end event: %v\n", err)
    		} else {
    			log.Println("Event ended.")
    		}
    	}, chrono.WithTime(endTime)); err != nil {
    		log.Fatalf("Failed to schedule event end time: %v\n", err)
    		return nil, err
    	}
    

    My question is: Will the fact that I am not shutting down the scheduler affect the performance of my application? If it will, then how should I do it? Thank you in advance for your attention.

    question 
    opened by yufeng1707 1
  • CronExpression not working inside docker

    CronExpression not working inside docker

    CronExpression can be scheduled but never gets executed.

    method: ScheduleWithCron(..., ..., chrono.WithLocation("Europe/Berlin")) expression: does not matter, also */1 * * * * not working docker-file to build and run:

    # The base go-image
    FROM golang:1.18-alpine as build
    # Create a directory for the app
    RUN mkdir /app
     # Copy all files from the current directory to the app directory
    COPY ./src /app
     # Set working directory
    WORKDIR /app
    # go build will build an executable file named tics in the current directory
    RUN go build -o tics
    FROM alpine:latest AS bin
    # copy from temporary "build"-image to the current
    copy --from=build /app/tics /tics
    copy ./tics.yml /tics.yml
    EXPOSE 3222
    RUN /bin/sh
    # Run the tics executable
    ENTRYPOINT ./tics
    

    running the same source outside docker as an executable works.

    do you have any ideas?

    bug critical 
    opened by peatle-mibt 1
  • End of month support?

    End of month support?

    is end of month supported? I don't seem to get errors running 0 0 21 L * ? *

    I definitely don't see it in the code, just curious if I'm missing something here,

    thank you.

    enhancement question 
    opened by guycipher 1
  • Add Marker support to be able to schedule tasks

    Add Marker support to be able to schedule tasks

    This feature makes it easier to schedule task by using markers and code generation. The following markers should be added, they will be enough for now.

    • +chrono:scheduled. This should have the following arguments. FixedDelay, FixedRate, Cron
    • +chrono:enable-scheduling (main method should be marked with this annotation, it will enable support for scheduling)

    The simple rule that we need to follow to marker a method with +chrono:scheduled is: The method should have the method signature as shown below. (If not, the method will be ignored or an error message will be shown.)

    func(ctx context.Context)
    

    Please investigate how to support this feature.

    This feature will come with the next release version which is 1.1.0 and except that there will be no API changes or new features.

    enhancement 
    opened by burakkoken 0
Releases(v1.1.0)
Owner
Procyon
Procyon is a powerful web framework written in Go
Procyon
Scheduler - Scheduler package is a zero-dependency scheduling library for Go

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

Javad Rajabzade 4 Jan 14, 2022
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

Nano GPU 82 Jun 22, 2022
Statefulset-scheduler (aka sfs-scheduler)

statefulset-scheduler (aka sfs-scheduler) Installation I already upload docker i

Onur Yartaşı 2 Dec 19, 2021
Scheduler: the scheduler of distbuild written in Golang

scheduler Introduction scheduler is the scheduler of distbuild written in Go. Pr

distbuild 0 Feb 9, 2022
Linstor-scheduler-extender - LINSTOR scheduler extender plugin for Kubernetes

linstor-scheduler-extender LINSTOR scheduler extender plugin for Kubernetes whic

Andrei Kvapil 1 Feb 14, 2022
Crane scheduler is a Kubernetes scheduler which can schedule pod based on actual node load.

Crane-scheduler Overview Crane-scheduler is a collection of scheduler plugins based on scheduler framework, including: Dynamic scheuler: a load-aware

Crane 32 Jun 16, 2022
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,

Jay Ehsaniara 22 Jun 11, 2022
Go distributed task scheduler

Go distributed task scheduler

Nuggets 1 Nov 13, 2021
Task Timer (tt) is a dead simple TUI task timer

tasktimer Task Timer (tt) is a dead simple TUI task timer Usage To get started, just run tt: tt You'll be presented with something like this: You can

Carlos Alexandro Becker 230 Jun 28, 2022
Gotask - A simple task queue is stripped when the program is written to achieve the task delivery function

gotask The simple task queue is stripped when the program is written to achieve

SaiRson 4 Feb 14, 2022
personal tweet scheduler - it needs my guidance now for it to work for you - it works on my mac - will release it someday

tit tit daemon write tests automate build & install plist replace {{path_for_titd_executable}} accordingly. <?xml version="1.0" encoding="UTF-8"?> <!D

Gyan Prakash Karn 0 Feb 4, 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

Supratim Samanta 49 May 3, 2022
Chadburn is a scheduler alternative to cron, built on Go and designed for Docker environments.

Chadburn - a job scheduler Chadburn is a modern and low footprint job scheduler for docker environments, written in Go. Chadburn aims to be a replacem

PremoWeb Internet Services 29 Jun 19, 2022
GPU Sharing Scheduler for Kubernetes Cluster

GPU Sharing Scheduler Extender in Kubernetes Overview More and more data scientists run their Nvidia GPU based inference tasks on Kubernetes. Some of

Aliyun (Alibaba Cloud) Container Service 922 Jun 21, 2022
Package tasks is an easy to use in-process scheduler for recurring tasks in Go

Tasks Package tasks is an easy to use in-process scheduler for recurring tasks in Go. Tasks is focused on high frequency tasks that run quick, and oft

Benjamin Cane 97 Jun 20, 2022
A simple job scheduler backed by Postgres.

A simple job scheduler backed by Postgres used in production at https://operand.ai. Setup needs two environment variables, SECRET and ENDPOINT. The se

Morgan Gallant 8 Jun 15, 2022
cpuworker - A Customized Goroutine Scheduler over Golang Runtime

cpuworker Status Working in process. Run the Demo Make sure the GOMAXPROCS is bigger than 1 and there is at least GOMAXPROCS physical OS threads avail

Sen Han 115 Jun 21, 2022
A Framework for FaaS load balancing | stack-scheduler repository|

P2PFaaS A Framework for FaaS load balancing | stack-scheduler repository Introduction The P2PFaaS is a framework that allows you to implement a load b

null 0 Oct 29, 2021
A sample to showcase how to create a k8s scheduler extender

sample-scheduler-extender A sample to showcase how to create a k8s scheduler extender. UPDATE on 2020.6.10 Switch go module, and wire dependencies to

null 0 Nov 17, 2021