Skip to content

banbox/cron

 
 

Repository files navigation

Cron - Go Language Task Scheduler

中文文档

A powerful Go cron expression parser and task scheduler that supports standard cron syntax, second-level precision, timezone control, and custom clock mechanisms.

Forked from robfig/cron

Core Features

  • Standard Cron Syntax - Default support for standard 5-field cron expressions (minute, hour, day, month, weekday); optional second field support
  • Predefined Schedules - Support for convenient expressions like @hourly, @daily, @weekly, @monthly, @yearly
  • Fixed Intervals - Fixed time interval scheduling using @every syntax
  • Timezone Support - Global and per-task timezone configuration
  • Dynamic Management - Add, remove, and view tasks at runtime
  • Thread-Safe - All operations are carefully designed to ensure concurrency safety
  • Multiple Clocks - Support for default system clock, simulated clock, and custom clocks

Multiple Clock Support

Free control of time through the Clock interface, supporting:

  • DefaultClock - Uses system clock (default)
  • FakeClock - Simulated clock for unit testing
  • Custom Implementation - Such as passing in NTP precise network time

Installation

go get github.com/banbox/cron/v3

Requires Go 1.11 or higher (using Go Modules).

Quick Start

Basic Usage

package main

import (
    "fmt"
    "github.com/banbox/cron/v3"
)

func main() {
    c := cron.New()
    
    // Execute at the 30th minute of every hour
    c.AddFunc("30 * * * *", func() {
        fmt.Println("Executes once per hour")
    })
    
    // Start the scheduler
    c.Start()
    
    // Block main program
    select {}
}

More Examples

// Support for second-level precision
c := cron.New(cron.WithSeconds())

// Execute every second
c.AddFunc("* * * * * *", func() {
    fmt.Println("Executes every second")
})

// @hourly, @daily, @weekly, @monthly, @yearly
c.AddFunc("@hourly", func() { fmt.Println("Every hour") })

// Execute every 1 hour 30 minutes
c.AddFunc("@every 1h30m", func() {
    fmt.Println("Executes every 90 minutes")
})


c.Start()

Timezone Configuration

import "time"

// Global timezone setting
loc, _ := time.LoadLocation("Asia/Shanghai")
c := cron.New(cron.WithClock(cron.NewDefaultClock(loc)))

// Specify timezone for individual task
c.AddFunc("CRON_TZ=Asia/Tokyo 0 6 * * *", func() {
    fmt.Println("Executes at 6 AM Tokyo time every day")
})

c.Start()

Task Management

c := cron.New()

// Add task and get ID
id, _ := c.AddFunc("@every 1m", func() {
    fmt.Println("Task executing")
})

c.Start()

// View all tasks
for _, entry := range c.Entries() {
    fmt.Printf("Task %d: Next execution time %v\n", entry.ID, entry.Next)
}

// Remove task
c.Remove(id)

// Stop scheduler
ctx := c.Stop()
<-ctx.Done() // Wait for all running tasks to complete

Using the Job Interface

type MyJob struct {
    Name string
}

func (j MyJob) Run() {
    fmt.Printf("Executing task: %s\n", j.Name)
}

c := cron.New()
c.AddJob("@every 1m", MyJob{Name: "Data Sync"})
c.Start()

FakeClock Unit Testing

func TestMultipleExecutions(t *testing.T) {
    startTime := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)
    fakeClock := cron.NewFakeClock(time.UTC, startTime)
    
    c := cron.New(cron.WithClock(fakeClock), cron.WithSeconds())
    
    count := 0
    c.AddFunc("0 0 * * * *", func() { count++ })
    
    c.Start()
    defer c.Stop()
    
    // Advance 24 hours, should execute 24 times
    c.RunTo(startTime.Add(24 * time.Hour))
    
    if count != 24 {
        t.Errorf("Expected 24 executions, got %d", count)
    }
}

NTP Time Source

cron has built-in bntp support, allowing you to use NTP as a time source (standard network time) to ensure tasks are triggered accurately at the correct network time.

package main

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

func main() {
    // Create cron scheduler using ntp time source
    loc, _ := time.LoadLocation("Asia/Shanghai")
    ntpClock := NewNtpClock(loc, bntp.LangGlobal)
    
    c := cron.New(cron.WithClock(ntpClock))
    
    // Add task
    c.AddFunc("* * * * *", func() {
        realTime := bntp.UTCStamp()
        sysTime := time.Now().UnixMilli()
        fmt.Println("system: %d, real: %d", sysTime, realTime)
    })
    
    c.Start()
    
    // Block main program
    select {}
}

Other Time Sources

You can also use other custom time sources, but you need to implement the Clock interface. You can refer to NtpClock as an example.

Then use the cron.WithClock() option to pass in your custom time source.

Cron Expression Examples (5 fields)

30 * * * *        At the 30th minute of every hour
0 0 * * *         Every day at midnight
0 0 1 * *         First day of every month at midnight
0 0 * * 0         Every Sunday at midnight
*/15 * * * *      Every 15 minutes
0 9-17 * * *      Every hour from 9 AM to 5 PM

License

MIT License

About

a cron library for go

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Go 100.0%