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) errorJobInfo
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
| Function | Signature | Description |
|---|---|---|
New | func New(cfg SchedulerConfig) Scheduler | Creates a new scheduler instance |
Register | func (s *Scheduler) Register(name string, schedule string, fn JobFunc) error | Registers a named job with a cron expression |
Start | func (s *Scheduler) Start(ctx context.Context) error | Starts the scheduler (non-blocking) |
Stop | func (s *Scheduler) Stop(ctx context.Context) error | Gracefully stops the scheduler |
Schedule Expressions
The scheduler supports standard cron expressions and predefined shortcuts.
| Expression | Description |
|---|---|
* * * * * | Every minute |
0 * * * * | Every hour |
0 0 * * * | Every day at midnight |
0 0 * * 0 | Every Sunday at midnight |
*/5 * * * * | Every 5 minutes |
0 9 * * 1-5 | Weekdays at 9:00 AM |
@every 30s | Every 30 seconds |
@every 5m | Every 5 minutes |
@hourly | Every hour |
@daily | Every day at midnight |
@weekly | Every 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
})Related Pages
Last updated on