cron

package module
v1.5.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 28, 2025 License: BSD-2-Clause Imports: 9 Imported by: 7

README

Cron

A Go library for robust cron job scheduling with multiple execution strategies, observability, and reliability features.

Installation

go get github.com/bborbe/cron

Quick Start

Basic Usage
package main

import (
    "context"
    "fmt"
    
    "github.com/bborbe/cron"
    "github.com/bborbe/run"
)

func main() {
    ctx := context.Background()
    
    // Create an action to run
    action := run.Func(func(ctx context.Context) error {
        fmt.Println("Job executed!")
        return nil
    })
    
    // Expression-based scheduling
    cronJob := cron.NewCronJob(false, cron.Expression("@every 1h"), 0, action)
    cronJob.Run(ctx)
}
Enhanced Usage with Options
package main

import (
    "context"
    "time"
    
    "github.com/bborbe/cron"
    "github.com/bborbe/run"
)

func main() {
    ctx := context.Background()
    
    action := run.Func(func(ctx context.Context) error {
        // Your job logic here
        return nil
    })
    
    // Configure options
    options := cron.CronJobOptions{
        Name:          "my-important-job",
        EnableMetrics: true,
        Timeout:       5 * time.Minute,
        ParallelSkip:  true,
    }
    
    // Create job with options
    cronJob := cron.NewCronJobWithOptions(
        false,                      // not one-time
        cron.Expression("0 */15 * * * ?"), // every 15 minutes
        0,                          // no wait duration
        action,
        options,
    )
    
    cronJob.Run(ctx)
}

Execution Strategies

The library automatically selects the appropriate execution strategy based on the parameters provided to NewCronJob or NewCronJobWithOptions:

1. Expression-Based (Cron Expressions)

Uses standard cron expressions or special formats:

// Every hour
cronJob := cron.NewCronJob(false, cron.Expression("@every 1h"), 0, action)

// Every 15 minutes using cron syntax
cronJob := cron.NewCronJob(false, cron.Expression("0 */15 * * * ?"), 0, action)

// Daily at 2:30 AM
cronJob := cron.NewCronJob(false, cron.Expression("0 30 2 * * ?"), 0, action)
2. Duration-Based (Intervals)

Uses Go time.Duration for simple intervals:

// Every 30 seconds
cronJob := cron.NewCronJob(false, "", 30*time.Second, action)

// Every 5 minutes
cronJob := cron.NewCronJob(false, "", 5*time.Minute, action)
3. One-Time Execution

Executes the job once immediately:

// Run once
cronJob := cron.NewCronJob(true, "", 0, action)

Configuration Options

The CronJobOptions struct provides fine-grained control over job behavior:

type CronJobOptions struct {
    Name          string        // Job name for metrics and logging
    EnableMetrics bool          // Enable Prometheus metrics collection  
    Timeout       time.Duration // Execution timeout (0 = disabled)
    ParallelSkip  bool          // Prevent concurrent executions
}
Default Options
options := cron.DefaultCronJobOptions()
// Returns:
// {
//     Name:          "unnamed-cron", 
//     EnableMetrics: false,
//     Timeout:       0,
//     ParallelSkip:  false,
// }

Wrapper Functions

For maximum flexibility, you can use wrapper functions directly:

Metrics Wrapper
import "github.com/prometheus/client_golang/prometheus"

// Wrap any action with metrics
wrappedAction := cron.WrapWithMetrics("job-name", originalAction)

Metrics Collected:

  • cron_job_started{name="job-name"} - Number of job starts
  • cron_job_completed{name="job-name"} - Number of successful completions
  • cron_job_failed{name="job-name"} - Number of failures
  • cron_job_last_success{name="job-name"} - Timestamp of last success
Timeout Wrapper
// Add 5-minute timeout
wrappedAction := cron.WrapWithTimeout("job-name", 5*time.Minute, originalAction)

// Disable timeout (≤0 duration)
wrappedAction := cron.WrapWithTimeout("job-name", 0, originalAction)
Chaining Wrappers
// Chain multiple wrappers (order matters)
action := cron.WrapWithTimeout("my-job", 5*time.Minute, originalAction)
action = cron.WrapWithMetrics("my-job", action)

Monitoring and Observability

Prometheus Integration

When metrics are enabled, the library automatically registers Prometheus collectors. Expose them via HTTP:

import (
    "net/http"
    "github.com/prometheus/client_golang/prometheus/promhttp"
)

func main() {
    // Your cron jobs with EnableMetrics: true
    
    // Expose metrics endpoint
    http.Handle("/metrics", promhttp.Handler())
    http.ListenAndServe(":8080", nil)
}
Custom Metrics

Access the metrics interface directly:

metrics := cron.NewCronMetrics()
metrics.IncreaseStarted("custom-job")
metrics.IncreaseCompleted("custom-job") 
metrics.SetLastSuccessToCurrent("custom-job")

Error Handling

The library provides proper error propagation through all wrapper layers:

action := run.Func(func(ctx context.Context) error {
    return errors.New("job failed")
})

cronJob := cron.NewCronJobWithOptions(true, "", 0, action, options)
err := cronJob.Run(ctx)
if err != nil {
    // Handle error - will include context from wrappers
    log.Printf("Cron job failed: %v", err)
}

Testing

The library provides mock interfaces for testing:

//go:generate go run -mod=mod github.com/maxbrunsfeld/counterfeiter/v6 -generate

import "github.com/bborbe/cron/mocks"

func TestMyCronJob(t *testing.T) {
    mockCronJob := &mocks.CronJob{}
    mockMetrics := &mocks.CronMetrics{}
    
    // Set up expectations and test your code
}

Examples

Web Scraper with Monitoring
options := cron.CronJobOptions{
    Name:          "web-scraper",
    EnableMetrics: true,
    Timeout:       30 * time.Second,
    ParallelSkip:  true,
}

scraper := run.Func(func(ctx context.Context) error {
    // Scrape website logic
    return scrapeWebsite(ctx)
})

cronJob := cron.NewCronJobWithOptions(
    false,
    cron.Expression("0 */5 * * * ?"), // Every 5 minutes
    0,
    scraper,
    options,
)
Database Cleanup Job
cleanup := run.Func(func(ctx context.Context) error {
    return cleanupOldRecords(ctx)
})

options := cron.CronJobOptions{
    Name:          "db-cleanup",
    EnableMetrics: true,
    Timeout:       10 * time.Minute,
}

cronJob := cron.NewCronJobWithOptions(
    false,
    cron.Expression("0 0 2 * * ?"), // Daily at 2 AM
    0,
    cleanup,
    options,
)

License

BSD-style license. See LICENSE file for details.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CreateDefaultParser added in v1.2.0

func CreateDefaultParser() cron.Parser

func NewCronJob

func NewCronJob(
	oneTime bool,
	expression Expression,
	wait time.Duration,
	action run.Runnable,
) run.Runnable

func NewCronJobWithOptions added in v1.4.0

func NewCronJobWithOptions(
	oneTime bool,
	expression Expression,
	wait time.Duration,
	action run.Runnable,
	options Options,
) run.Runnable

func NewExpressionCron

func NewExpressionCron(
	expression Expression,
	action run.Runnable,
) run.Runnable

func NewExpressionCronWithOptions added in v1.5.0

func NewExpressionCronWithOptions(
	expression Expression,
	action run.Runnable,
	options Options,
) run.Runnable

func NewIntervalCron added in v1.3.1

func NewIntervalCron(
	wait time.Duration,
	action run.Runnable,
) run.Runnable

func NewIntervalCronWithOptions added in v1.5.0

func NewIntervalCronWithOptions(
	wait time.Duration,
	action run.Runnable,
	options Options,
) run.Runnable

func NewOneTimeCron

func NewOneTimeCron(
	action run.Runnable,
) run.Runnable

func NewOneTimeCronWithOptions added in v1.5.0

func NewOneTimeCronWithOptions(
	action run.Runnable,
	options Options,
) run.Runnable

func NewWaitCron

func NewWaitCron(
	wait time.Duration,
	action run.Runnable,
) run.Runnable

NewWaitCron Deprecated: use NewIntervalCron instead

func WrapWithMetrics added in v1.4.0

func WrapWithMetrics(name string, fn run.Runnable) run.Runnable

func WrapWithOptions added in v1.5.0

func WrapWithOptions(action run.Runnable, options Options) run.Runnable

WrapWithOptions applies all configured wrappers to an action based on the provided options. Wrappers are applied in this order (innermost to outermost): 1. Timeout wrapper (if timeout > 0) 2. Metrics wrapper (if enabled) 3. Parallel skip wrapper (if enabled)

func WrapWithTimeout added in v1.4.0

func WrapWithTimeout(name string, timeout time.Duration, fn run.Runnable) run.Runnable

Types

type Cron

type Cron interface {
	Run(ctx context.Context) error
}

type Expression added in v1.2.0

type Expression string

Expression of the cron cron.Second | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor every second: * * * * * ? every minute 0 * * * * ? every 15 minute 0 */15 * * * ? every hour: 0 0 * * * ? every hour on sunday: 0 0 * * * 0

func (Expression) Bytes added in v1.2.0

func (e Expression) Bytes() []byte

func (Expression) Ptr added in v1.2.0

func (e Expression) Ptr() *Expression

func (Expression) String added in v1.2.0

func (e Expression) String() string

type Metrics added in v1.4.0

type Metrics interface {
	IncreaseStarted(name string)
	IncreaseFailed(name string)
	IncreaseCompleted(name string)
	SetLastSuccessToCurrent(name string)
}

func NewMetrics added in v1.4.0

func NewMetrics() Metrics

type Options added in v1.5.1

type Options struct {
	Name          string
	EnableMetrics bool
	Timeout       libtime.Duration
	ParallelSkip  bool
}

func DefaultOptions added in v1.5.1

func DefaultOptions() Options

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL