scheduler
The scheduler package provides periodic task execution using cron expressions.
Core Components:
Scheduler: Executes a runner according to a cron schedule. ImplementsRunnerinterface so it can be used as anapplicationservice.New(cronExpr, runner): Creates a new scheduler with a cron expression.
Supported cron formats:
- Standard 5-field cron:
"minute hour day month weekday"(e.g.,"0 9 * * MON-FRI") - Custom descriptors:
@yearly,@monthly,@weekly,@daily,@hourly - Interval syntax:
@every 30s,@every 5m,@every 2h(use this for simple intervals)
Full package docs at pkg.go.dev
Step-by-step guide
Section titled “Step-by-step guide”-
Create a task function
func scheduledTask(ctx context.Context) error {log.InfoContext(ctx, "scheduled task executed")return nil}The function receives a context with a unique trace ID for each execution.
-
Create a scheduler
s, err := scheduler.New("@every 1s", application.RunnerFunc(scheduledTask))if err != nil {log.Fatal(err)}First argument is a cron expression (use
@everysyntax for intervals). Second is anyapplication.Runnerimplementation. Useapplication.RunnerFuncto wrap a function. -
Run the scheduler
err := s.Run(ctx)The scheduler blocks and executes the task at each interval until the context is cancelled.
Expected output:
time=2025-01-01T12:00:01.000+00:00 level=INFO msg="scheduler task started" traceID=abc-123time=2025-01-01T12:00:01.000+00:00 level=INFO msg="scheduled task executed" traceID=abc-123time=2025-01-01T12:00:01.000+00:00 level=INFO msg="scheduler task finished" traceID=abc-123time=2025-01-01T12:00:02.000+00:00 level=INFO msg="scheduler task started" traceID=def-456time=2025-01-01T12:00:02.000+00:00 level=INFO msg="scheduled task executed" traceID=def-456time=2025-01-01T12:00:02.000+00:00 level=INFO msg="scheduler task finished" traceID=def-456 -
Handle errors
func scheduledTask(ctx context.Context) error {if err := doWork(); err != nil {return err // Logged automatically, scheduler continues}return nil}Errors returned from the task are logged but do not stop the scheduler. The next execution proceeds as normal.
Using with Application
Section titled “Using with Application”Since Scheduler implements the Runner interface, it can be registered as a service in an Application:
app := application.New()
s, err := scheduler.New("@every 1m", application.RunnerFunc(scheduledTask))if err != nil { log.Fatal(err)}
app.RegisterService("scheduler", s)
app.Run(ctx)The scheduler starts when the application runs and stops when the application shuts down.
Cron Syntax Guide
Section titled “Cron Syntax Guide”The scheduler uses cron expressions for all scheduling needs, from simple intervals to complex patterns.
Common Cron Patterns
Section titled “Common Cron Patterns”Standard Cron Syntax (minute hour day month weekday):
// Every 5 minutesscheduler.New("*/5 * * * *", runner)
// Every hour at minute 0scheduler.New("0 * * * *", runner)
// Every 2 hours at minute 0scheduler.New("0 */2 * * *", runner)
// Every day at 9:30 AMscheduler.New("30 9 * * *", runner)
// Weekdays at 9 AMscheduler.New("0 9 * * MON-FRI", runner)
// First day of every month at midnightscheduler.New("0 0 1 * *", runner)Custom Descriptors:
// Every hour (at minute 0)scheduler.New("@hourly", runner)
// Every day at midnightscheduler.New("@daily", runner)
// Every Sunday at midnightscheduler.New("@weekly", runner)
// First day of month at midnightscheduler.New("@monthly", runner)
// January 1st at midnightscheduler.New("@yearly", runner)Interval Syntax:
// Every 30 secondsscheduler.New("@every 30s", runner)
// Every 5 minutesscheduler.New("@every 5m", runner)
// Every 2 hoursscheduler.New("@every 2h", runner)
// Every 12 hoursscheduler.New("@every 12h", runner)Choosing the Right Syntax
Section titled “Choosing the Right Syntax”| Use Case | Syntax | Example |
|---|---|---|
| Simple fixed interval | @every | @every 5m |
| Specific time of day | Standard cron | 30 9 * * * (9:30 AM daily) |
| Weekday-specific | Standard cron | 0 9 * * MON-FRI |
| Complex patterns | Standard cron | */15 9-17 * * MON-FRI |
| Common schedules | Descriptors | @daily, @hourly |
Examples
// Simple interval - runs every 5 minutes starting immediatelys, _ := scheduler.New("@every 5m", runner)
// Clock-aligned - runs at :00, :05, :10, :15, etc.s, _ := scheduler.New("*/5 * * * *", runner)
// Daily at specific times, _ := scheduler.New("30 9 * * *", runner) // 9:30 AM daily
// Weekday business hours onlys, _ := scheduler.New("0 9 * * MON-FRI", runner) // 9 AM weekdaysComplete examples
Section titled “Complete examples”Simple Interval Scheduler
Section titled “Simple Interval Scheduler”package main
import ( "context" "time"
"github.com/platforma-dev/platforma/application" "github.com/platforma-dev/platforma/log" "github.com/platforma-dev/platforma/scheduler")
func scheduledTask(ctx context.Context) error { log.InfoContext(ctx, "scheduled task executed") return nil}
func main() { ctx, cancel := context.WithCancel(context.Background())
s, err := scheduler.New("@every 1s", application.RunnerFunc(scheduledTask)) if err != nil { log.ErrorContext(ctx, "failed to create scheduler", "error", err) return }
go func() { time.Sleep(3500 * time.Millisecond) cancel() }()
s.Run(ctx)}Advanced Cron Patterns
Section titled “Advanced Cron Patterns”package main
import ( "context" "fmt" "time"
"github.com/platforma-dev/platforma/application" "github.com/platforma-dev/platforma/log" "github.com/platforma-dev/platforma/scheduler")
func dailyBackup(ctx context.Context) error { log.InfoContext(ctx, "executing daily backup task") return nil}
func weekdayReport(ctx context.Context) error { log.InfoContext(ctx, "generating weekday report") return nil}
func frequentHealthCheck(ctx context.Context) error { log.InfoContext(ctx, "performing health check") return nil}
func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel()
// Example 1: Using @every syntax - every 5 seconds s1, err := scheduler.New("@every 5s", application.RunnerFunc(func(ctx context.Context) error { log.InfoContext(ctx, "@every syntax: every 5 seconds") return nil })) if err != nil { log.ErrorContext(ctx, "failed to create scheduler 1", "error", err) return }
// Example 2: Using @every syntax - every 3 seconds s2, err := scheduler.New("@every 3s", application.RunnerFunc(func(ctx context.Context) error { log.InfoContext(ctx, "@every syntax: every 3 seconds") return nil })) if err != nil { log.ErrorContext(ctx, "failed to create scheduler 2", "error", err) return }
// Example 3: Daily task (would run at midnight, but won't execute in this demo) s3, err := scheduler.New("@daily", application.RunnerFunc(dailyBackup)) if err != nil { log.ErrorContext(ctx, "failed to create scheduler 3", "error", err) return }
// Example 4: Weekday task (would run at 9 AM on weekdays, won't execute in this demo) s4, err := scheduler.New("0 9 * * MON-FRI", application.RunnerFunc(weekdayReport)) if err != nil { log.ErrorContext(ctx, "failed to create scheduler 4", "error", err) return }
// Example 5: Hourly task (won't execute in this demo) s5, err := scheduler.New("@hourly", application.RunnerFunc(frequentHealthCheck)) if err != nil { log.ErrorContext(ctx, "failed to create scheduler 5", "error", err) return }
fmt.Println("Starting cron scheduler demo...") fmt.Println("Active schedulers:") fmt.Println(" 1. Every 5 seconds (@every 5s)") fmt.Println(" 2. Every 3 seconds (@every 3s)") fmt.Println(" 3. Daily at midnight (@daily) - won't execute in demo") fmt.Println(" 4. Weekdays at 9 AM (0 9 * * MON-FRI) - won't execute in demo") fmt.Println(" 5. Hourly (@hourly) - won't execute in demo") fmt.Println() fmt.Println("Watch the logs for executions. Demo will run for 15 seconds.") fmt.Println()
// Start all schedulers in background go s1.Run(ctx) go s2.Run(ctx) go s3.Run(ctx) go s4.Run(ctx) go s5.Run(ctx)
// Run for 15 seconds to demonstrate the frequent tasks time.Sleep(15 * time.Second) cancel()
// Allow graceful shutdown time.Sleep(100 * time.Millisecond)
fmt.Println() fmt.Println("Demo completed!")}