Note
This content is translated by LLM. Original text can be found here
Ultra-lightweight Golang scheduler supporting standard cron expressions, custom descriptors, and custom intervals. A minimalist scheduler for Go that makes scheduling effortless.
Originally designed for the scheduling functionality used in threat score decay calculations for pardnchiu/go-ip-sentry.
Built with Go's standard library heap, focusing on core functionality with minimal memory usage and zero learning cost - if you can write cron expressions, you can use this
Supports standard cron expressions, custom descriptors (@hourly, @daily, @weekly, etc.), and custom interval (@every) syntax
Min-heap based task scheduling algorithm with concurrent task execution and management, panic recovery mechanism, and dynamic task addition/removal, ensuring optimal performance in high-volume task scenarios
Click to view
flowchart TD
A[Initialize] --> B[Setup Logger]
B --> C[Initialize Task Heap]
C --> D{Already Running?}
D -->|Yes| D1[No Action]
D -->|No| D2[Start Execution]
D2 --> E[Calculate Initial Task Times]
E --> F[Initialize Min Heap]
F --> G[Start Main Loop]
G --> H{Check Heap Status}
G -->|No Tasks<br>Wait for Events| Q[Listen for Events]
G -->|Has Tasks<br>Set Timer to Next Task| Q
Q --> R{Event Type}
R -->|Timer Expires| R1[Execute Due Tasks]
R -->|Add Task| R2[Add to Heap]
R -->|Remove Task| R3[Remove from Heap]
R -->|Stop Signal| R4[Cleanup and Exit]
R1 --> S[Pop Task from Heap]
S --> T{Check if Enabled}
T -->|Disabled| T0[Skip Task]
T0 --> G
T -->|Enabled| T1{Execute Task Function}
T1 --> T11[Calculate Next Execution Time]
T1 -->|Panic| T10[Recover]
T10 --> T11[Calculate Next Execution Time]
T11 --> U[Re-add to Heap if Recurring]
R2 --> V[Parse Schedule]
V --> W[Create Task Object]
W --> X[Add to Heap]
R3 --> Y[Find Task by ID]
Y --> Z[Mark as Disabled]
Z --> AA[Remove from Heap]
U --> G
X --> G
AA --> G
R4 --> BB[Wait for Running Tasks to Complete]
BB --> CC[Close Channels]
CC --> DD[Scheduler Stopped]
go get github.com/pardnchiu/go-cronpackage main
import (
"fmt"
"log"
"time"
cron "github.com/pardnchiu/go-cron"
)
func main() {
// Initialize (optional configuration)
scheduler, err := cron.New(cron.Config{
Log: &cron.Log{Stdout: true},
Location: time.Local,
})
if err != nil {
log.Fatal(err)
}
// Start scheduler
scheduler.Start()
// Add tasks
id1, _ := scheduler.Add("@daily", func() {
fmt.Println("Daily execution")
}, "Backup task")
id2, _ := scheduler.Add("@every 5m", func() {
fmt.Println("Execute every 5 minutes")
})
// View task list
tasks := scheduler.List()
fmt.Printf("Currently have %d tasks\n", len(tasks))
// Remove specific task
scheduler.Remove(id1)
// Remove all tasks
scheduler.RemoveAll()
// Graceful shutdown
ctx := scheduler.Stop()
<-ctx.Done()
}type Config struct {
Log *Log // Logger configuration
Location *time.Location // Timezone setting (default: time.Local)
}
type Log struct {
Path string // Log file path (default: ./logs/cron.log)
Stdout bool // Output to stdout (default: false)
MaxSize int64 // Maximum log file size in bytes (default: 16MB)
MaxBackup int // Number of backup files to retain (default: 5)
Type string // Output format: "json" for slog standard, "text" for tree format (default: "text")
}5-field format: minute hour day month weekday
// Every minute
scheduler.Add("* * * * *", task)
// Daily at midnight
scheduler.Add("0 0 * * *", task)
// Weekdays at 9 AM
scheduler.Add("0 9 * * 1-5", task)
// Every 15 minutes
scheduler.Add("*/15 * * * *", task)
// First day of month at 6 AM
scheduler.Add("0 6 1 * *", task)// January 1st at midnight
scheduler.Add("@yearly", task)
// First day of month at midnight
scheduler.Add("@monthly", task)
// Every Sunday at midnight
scheduler.Add("@weekly", task)
// Daily at midnight
scheduler.Add("@daily", task)
// Every hour on the hour
scheduler.Add("@hourly", task)
// Every 30 seconds
scheduler.Add("@every 30s", task)
// Every 5 minutes
scheduler.Add("@every 5m", task)
// Every 2 hours
scheduler.Add("@every 2h", task)
// Every 12 hours
scheduler.Add("@every 12h", task)-
New - Create new scheduler instance
scheduler, err := cron.New(config)
- Sets up task heap and communication channels
-
Start - Start scheduler instance
scheduler.Start()
- Starts scheduling loop
-
Stop - Gracefully stop scheduler
ctx := scheduler.Stop() <-ctx.Done() // Wait for all tasks to complete
- Sends stop signal to main loop
- Returns context that completes when all running tasks finish
- Ensures graceful shutdown without interrupting tasks
-
Add - Add scheduled task
taskID, err := scheduler.Add("0 */2 * * *", func() { // Task logic })
- Parses schedule syntax
- Generates unique task ID for management
-
Remove - Cancel task schedule
scheduler.Remove(taskID)
- Removes task from scheduling queue
- Safe to call regardless of scheduler state
-
RemoveAll - Remove all tasks
scheduler.RemoveAll()
- Immediately removes all scheduled tasks
- Does not affect currently running tasks
-
List - Get task list
tasks := scheduler.List()
- Task dependency management similar to php-async
- Pre-dependencies: Task B executes after Task A completes
- Post-dependencies: Task B executes before Task A starts
- Multiple dependencies: Task C waits for both Tasks A and B to complete before executing
This project is licensed under the MIT License.
©️ 2025 邱敬幃 Pardn Chiu