Skip to Content

Scheduler

The scheduler package provides cron-based job scheduling for recurring tasks. It supports standard cron expressions, job registration, overlapping execution control, and graceful shutdown.

Import

import "github.com/gofastadev/gofasta/pkg/scheduler"

Key Types

Scheduler

type Scheduler interface { Register(name string, schedule string, fn JobFunc) error Start(ctx context.Context) error Stop(ctx context.Context) error IsRunning() bool Jobs() []JobInfo }

JobFunc

type JobFunc func(ctx context.Context) error

JobInfo

type JobInfo struct { Name string `json:"name"` Schedule string `json:"schedule"` LastRun time.Time `json:"last_run"` NextRun time.Time `json:"next_run"` RunCount int64 `json:"run_count"` ErrorCount int64 `json:"error_count"` }

SchedulerConfig

type SchedulerConfig struct { AllowOverlap bool `yaml:"allow_overlap"` Timezone string `yaml:"timezone"` Logger logger.Logger }

Key Functions

FunctionSignatureDescription
Newfunc New(cfg SchedulerConfig) SchedulerCreates a new scheduler instance
Registerfunc (s *Scheduler) Register(name string, schedule string, fn JobFunc) errorRegisters a named job with a cron expression
Startfunc (s *Scheduler) Start(ctx context.Context) errorStarts the scheduler (non-blocking)
Stopfunc (s *Scheduler) Stop(ctx context.Context) errorGracefully stops the scheduler

Schedule Expressions

The scheduler supports standard cron expressions and predefined shortcuts.

ExpressionDescription
* * * * *Every minute
0 * * * *Every hour
0 0 * * *Every day at midnight
0 0 * * 0Every Sunday at midnight
*/5 * * * *Every 5 minutes
0 9 * * 1-5Weekdays at 9:00 AM
@every 30sEvery 30 seconds
@every 5mEvery 5 minutes
@hourlyEvery hour
@dailyEvery day at midnight
@weeklyEvery Sunday at midnight

Usage

Basic Scheduling

sched := scheduler.New(scheduler.SchedulerConfig{ Timezone: "UTC", Logger: log, }) // Run every 5 minutes sched.Register("cleanup-sessions", "*/5 * * * *", func(ctx context.Context) error { log.Info("cleaning up expired sessions") return sessionStore.Cleanup(ctx) }) // Run daily at 2:00 AM sched.Register("generate-reports", "0 2 * * *", func(ctx context.Context) error { log.Info("generating daily reports") return reportService.GenerateDaily(ctx) }) // Run every 30 seconds sched.Register("health-ping", "@every 30s", func(ctx context.Context) error { return healthChecker.Ping(ctx) })

Starting and Stopping

// Start the scheduler (non-blocking) if err := sched.Start(ctx); err != nil { log.Fatal("failed to start scheduler", logger.Err(err)) } // Graceful shutdown quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() sched.Stop(shutdownCtx)

Listing Registered Jobs

for _, job := range sched.Jobs() { fmt.Printf("Job: %s, Schedule: %s, Last Run: %s, Next Run: %s\n", job.Name, job.Schedule, job.LastRun, job.NextRun) }

Preventing Overlapping Execution

By default, a job will not start a new execution if the previous one is still running. Set AllowOverlap to change this behavior.

sched := scheduler.New(scheduler.SchedulerConfig{ AllowOverlap: false, // default: jobs do not overlap })
  • Queue — Queue long-running jobs instead of running them inline
  • Logger — Log scheduler activity
  • Health — Monitor scheduler status in health checks
Last updated on