GitHub - pardnchiu/go-scheduler: (Golang Package) Scheduler with standard cron and task dependencies (original) (raw)

Note

This README was translated by ChatGPT 4o

Go Scheduler

Lightweight Golang scheduler supporting standard cron expressions, custom descriptors, custom intervals, and task dependencies. Easy scheduling with Go
Originally designed for the scheduling functionality used in threat score decay calculations for pardnchiu/go-ip-sentry

pkg card codecov version license Mentioned in Awesome Go
readme readme

Core Features

Flexible Syntax

Supports standard cron expressions, custom descriptors (@hourly, @daily, @weekly, etc.), and custom interval (@every) syntax. Zero learning curve - if you know cron expressions, you can use it.

Task Dependencies

Supports prerequisite dependency tasks, multiple dependencies, dependency timeout control, and failure handling mechanisms.

Efficient Architecture

Uses Golang standard library heap, focusing on core functionality. Min-heap based task scheduling with concurrent task execution and management, featuring panic recovery and dynamic task add/remove capabilities, ensuring optimal performance in high-volume task scenarios.

Flowchart

Main Process

flowchart TD A[Initialize] --> B{Is Running?} B -->|No| B0[Start Execution] B0 --> C[Calculate Initial Tasks] C --> D[Initialize Tasks] D --> E[Start Main Loop] E --> H{Check Heap Status} E -->|No Tasks
Wait for Events| Q E -->|Has Tasks
Set Next Task Timer| Q B -->|Yes
Wait for Trigger| Q[Listen Events]

Q --> R{Event Type} R -->|Timer Expired| 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 --> R5[Calculate Next Execution Time] R5 --> E S --> T{Check if Enabled} T -->|Disabled| T0[Skip Task] T0 --> E T -->|Enabled| T1[Execute Task Function]

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]

X --> E AA --> E

R4 --> BB[Wait for Running Tasks to Complete] BB --> CC[Close Channels] CC --> DD[Scheduler Stopped]

Loading

Dependency Process

flowchart TD A[Task Added to Execution Queue] --> B{Check Dependencies} B -->|No Dependencies| B0[Skip Dependency Process] B0 --> Z[End] B -->|Has Dependencies| B1{Dependencies Complete?} B1 -->|No| B10[Wait for Dependencies] B10 --> C{Dependency Wait Timeout?} C -->|No| C0[Continue Waiting] C0 --> D{Dependency Resolved?} D -->|Failed
Mark Failed| V D -->|Completed| B11 D -->|Still Waiting| B10 C -->|Yes
Mark Failed| V B1 -->|Yes| B11[Execute] B11 -->|Mark Running| E{Task Timeout Exists?} E -->|No| E0[Execute Action] E0 --> R{Execution Result} R -->|Success
Mark Complete| V[Update Task Result] R -->|Error
Mark Failed| V R -->|Panic
Recover and Mark Failed| V E -->|Yes| E1{Task Timeout?} E1 -->|Timeout
Mark Failed
Trigger Timeout Action| V E1 -->|Not Timeout| E0 B1 -->|Failed
Mark Failed| V

V --> X[Record Execution Result]
X --> Y[Notify Dependent Tasks]
Y --> Z[End]

Loading

Dependencies

Usage

Installation

Note

Latest commit may change, recommended to use tagged versions
Commits containing only documentation updates or non-functional changes will be rebased later

go get github.com/pardnchiu/go-scheduler@[VERSION]

git clone --depth 1 --branch [VERSION] https://github.com/pardnchiu/go-scheduler.git

Initialization

Basic Usage

package main

import ( "fmt" "log" "time"

cron "github.com/pardnchiu/go-scheduler" )

func main() { // Initialize (optional configuration) scheduler, err := cron.New(cron.Config{ 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() }

Task Dependencies

package main

import ( "fmt" "log" "time"

cron "github.com/pardnchiu/go-scheduler" )

func main() { scheduler, err := cron.New(cron.Config{}) if err != nil { log.Fatal(err) }

scheduler.Start() defer func() { ctx := scheduler.Stop() <-ctx.Done() }()

// Task A: Data preparation taskA, _ := scheduler.Add("0 1 * * *", func() error { fmt.Println("Preparing data...") time.Sleep(2 * time.Second) return nil }, "Data preparation")

// Task B: Data processing
taskB, _ := scheduler.Add("0 2 * * *", func() error { fmt.Println("Processing data...") time.Sleep(3 * time.Second) return nil }, "Data processing")

// Task C: Report generation (depends on A and B) taskC, _ := scheduler.Add("0 3 * * *", func() error { fmt.Println("Generating report...") time.Sleep(1 * time.Second) return nil }, "Report generation", []Wait{{ID: taskA}, {ID: taskB}})

// Task D: Email sending (depends on C) _, _ = scheduler.Add("0 4 * * *", func() error { fmt.Println("Sending email...") return nil }, "Email notification", []Wait{{ID: taskC}})

time.Sleep(10 * time.Second) }

Configuration

type Config struct { Location *time.Location // Timezone setting (default: time.Local) }

Supported Formats

Standard

5-field format: minute hour day month weekday
Supports range syntax 1-5 and 1,3,5

// Every minute scheduler.Add("* * * * *", task)

// Daily at midnight scheduler.Add("0 0 * * *", task)

// Every 15 minutes scheduler.Add("*/15 * * * *", task)

// First day of month at 6 AM scheduler.Add("0 6 1 * *", task)

// Monday to Wednesday, and Friday scheduler.Add("0 0 * * 1-3,5", task)

Custom

// 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 (minimum interval: 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)

Available Functions

Scheduler Management

Task Management

Task Dependencies

Basic Usage

Dependency Examples

Failure handling strategies:

// Skip: Continue execution when dependency fails taskC, _ := scheduler.Add("0 3 * * *", func() error { fmt.Println("Generating report...") return nil }, "Report generation", []Wait{ {ID: taskA, State: Skip}, // Skip when taskA fails {ID: taskB, State: Stop}, // Stop when taskB fails (default) })

Custom timeout:

// Set independent wait time for each dependency taskC, _ := scheduler.Add("0 3 * * *", func() error { fmt.Println("Generating report...") return nil }, "Report generation", []Wait{ {ID: taskA, Delay: 30 * time.Second}, // Wait 30 seconds {ID: taskB, Delay: 45 * time.Second}, // Wait 45 seconds })

Combined usage:

// Combine failure strategies with custom timeout taskC, _ := scheduler.Add("0 3 * * *", func() error { fmt.Println("Generating report...") return nil }, "Report generation", []Wait{ {ID: taskA, Delay: 30 * time.Second, State: Skip}, {ID: taskB, Delay: 45 * time.Second, State: Stop}, })

Task Status

const ( TaskPending // Waiting TaskRunning // Running TaskCompleted // Completed TaskFailed // Failed / Timeout )

Timeout Mechanism

When execution time exceeds the set Delay:

Features

Upcoming Features

Enhanced Task Dependencies

Task Completion Trigger Refactor

License

This project is licensed under MIT.

Star

Star

Author

邱敬幃 Pardn Chiu


©️ 2025 邱敬幃 Pardn Chiu