Documentation
¶
Overview ¶
Package scheduler provides a GitHub Actions-inspired cron job scheduler.
Features:
- Standard cron expression syntax (5-field and 6-field formats)
- Timezone-aware scheduling
- Middleware pattern for cross-cutting concerns (logging, metrics, recovery)
- Graceful shutdown with context cancellation
- Zero external dependencies
Basic usage:
s := scheduler.New()
s.Register(&scheduler.Job{
Name: "daily-cleanup",
Schedule: "0 2 * * *", // 2 AM daily
Handler: func(ctx context.Context) error {
// Your cleanup logic here
return nil
},
})
s.Start()
defer s.Stop(context.Background())
With middleware:
s := scheduler.New(
scheduler.WithTimezone("America/New_York"),
scheduler.WithMiddleware(
scheduler.Recovery(),
scheduler.Logging(),
),
)
Example (Basic) ¶
Example demonstrates basic scheduler usage.
package main
import (
"context"
"fmt"
"time"
"github.com/usememos/memos/plugin/scheduler"
)
func main() {
s := scheduler.New()
s.Register(&scheduler.Job{
Name: "hello",
Schedule: "*/5 * * * *", // Every 5 minutes
Description: "Say hello",
Handler: func(_ context.Context) error {
fmt.Println("Hello from scheduler!")
return nil
},
})
s.Start()
defer s.Stop(context.Background())
// Scheduler runs in background
time.Sleep(100 * time.Millisecond)
}
Example (GracefulShutdown) ¶
Example demonstrates graceful shutdown with timeout.
package main
import (
"context"
"fmt"
"time"
"github.com/usememos/memos/plugin/scheduler"
)
func main() {
s := scheduler.New()
s.Register(&scheduler.Job{
Name: "long-running",
Schedule: "* * * * *",
Handler: func(ctx context.Context) error {
select {
case <-time.After(30 * time.Second):
fmt.Println("Job completed")
case <-ctx.Done():
fmt.Println("Job canceled, cleaning up...")
return ctx.Err()
}
return nil
},
})
s.Start()
// Simulate shutdown signal
time.Sleep(5 * time.Second)
// Give jobs 10 seconds to finish
shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := s.Stop(shutdownCtx); err != nil {
fmt.Printf("Shutdown error: %v\n", err)
}
}
Example (Middleware) ¶
Example demonstrates middleware usage.
package main
import (
"context"
"log/slog"
"os"
"time"
"github.com/usememos/memos/plugin/scheduler"
)
func main() {
logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
s := scheduler.New(
scheduler.WithMiddleware(
scheduler.Recovery(func(jobName string, r interface{}) {
logger.Error("Job panicked", "job", jobName, "panic", r)
}),
scheduler.Logging(&slogAdapter{logger}),
scheduler.Timeout(5*time.Minute),
),
)
s.Register(&scheduler.Job{
Name: "data-sync",
Schedule: "0 */2 * * *", // Every 2 hours
Handler: func(_ context.Context) error {
// Your sync logic here
return nil
},
})
s.Start()
defer s.Stop(context.Background())
}
// slogAdapter adapts slog.Logger to scheduler.Logger interface.
type slogAdapter struct {
logger *slog.Logger
}
func (a *slogAdapter) Info(msg string, args ...interface{}) {
a.logger.Info(msg, args...)
}
func (a *slogAdapter) Error(msg string, args ...interface{}) {
a.logger.Error(msg, args...)
}
Example (MultipleJobs) ¶
Example demonstrates multiple jobs with different schedules.
package main
import (
"context"
"fmt"
"github.com/usememos/memos/plugin/scheduler"
)
func main() {
s := scheduler.New()
// Cleanup old data every night at 2 AM
s.Register(&scheduler.Job{
Name: "cleanup",
Schedule: "0 2 * * *",
Tags: []string{"maintenance"},
Handler: func(_ context.Context) error {
fmt.Println("Cleaning up old data...")
return nil
},
})
// Health check every 5 minutes
s.Register(&scheduler.Job{
Name: "health-check",
Schedule: "*/5 * * * *",
Tags: []string{"monitoring"},
Handler: func(_ context.Context) error {
fmt.Println("Running health check...")
return nil
},
})
// Weekly backup on Sundays at 1 AM
s.Register(&scheduler.Job{
Name: "weekly-backup",
Schedule: "0 1 * * 0",
Tags: []string{"backup"},
Handler: func(_ context.Context) error {
fmt.Println("Creating weekly backup...")
return nil
},
})
s.Start()
defer s.Stop(context.Background())
}
Example (Timezone) ¶
Example demonstrates timezone-aware scheduling.
package main
import (
"context"
"fmt"
"github.com/usememos/memos/plugin/scheduler"
)
func main() {
s := scheduler.New(
scheduler.WithTimezone("America/New_York"),
)
s.Register(&scheduler.Job{
Name: "daily-report",
Schedule: "0 9 * * *", // 9 AM in New York
Handler: func(_ context.Context) error {
fmt.Println("Generating daily report...")
return nil
},
})
s.Start()
defer s.Stop(context.Background())
}
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func GetJobName ¶
GetJobName retrieves the job name from the context (public API). Returns empty string if not found.
Types ¶
type Job ¶
type Job struct {
// Name is a unique identifier for this job (required).
// Used for logging and metrics.
Name string
// Schedule is a cron expression defining when this job runs (required).
// Supports standard 5-field format: "minute hour day month weekday"
// Examples: "0 * * * *" (hourly), "0 0 * * *" (daily at midnight)
Schedule string
// Timezone for schedule evaluation (optional, defaults to UTC).
// Use IANA timezone names: "America/New_York", "Europe/London", etc.
Timezone string
// Handler is the function to execute when the job triggers (required).
Handler JobHandler
// Description provides human-readable context about what this job does (optional).
Description string
// Tags allow categorizing jobs for filtering/monitoring (optional).
Tags []string
}
Job represents a scheduled task.
type JobHandler ¶
JobHandler is the function signature for scheduled job handlers. The context passed to the handler will be canceled if the scheduler is shutting down.
type Logger ¶
type Logger interface {
Info(msg string, args ...interface{})
Error(msg string, args ...interface{})
}
Logger is a minimal logging interface.
type Middleware ¶
type Middleware func(JobHandler) JobHandler
Middleware wraps a JobHandler to add cross-cutting behavior.
func Chain ¶
func Chain(middlewares ...Middleware) Middleware
Chain combines multiple middleware into a single middleware. Middleware are applied in the order they're provided (left to right).
func Recovery ¶
func Recovery(onPanic func(jobName string, recovered interface{})) Middleware
Recovery recovers from panics in job handlers and converts them to errors.
func Timeout ¶
func Timeout(duration time.Duration) Middleware
Timeout wraps a job handler with a timeout.
type Option ¶
type Option func(*Scheduler)
Option configures a Scheduler.
func WithMiddleware ¶
func WithMiddleware(mw ...Middleware) Option
WithMiddleware sets middleware to wrap all job handlers.
func WithTimezone ¶
WithTimezone sets the default timezone for all jobs.
type Schedule ¶
type Schedule struct {
// contains filtered or unexported fields
}
Schedule represents a parsed cron expression.
func ParseCronExpression ¶
ParseCronExpression parses a cron expression and returns a Schedule. Supports both 5-field (minute hour day month weekday) and 6-field (second minute hour day month weekday) formats.
type Scheduler ¶
type Scheduler struct {
// contains filtered or unexported fields
}
Scheduler manages scheduled jobs.