Cron

Cron

Job scheduling with simple and distributed modes, retries, and admin API

Overview

github.com/xraph/forge/extensions/cron provides a cron job scheduler for Forge applications. It supports simple (single-node) and distributed (leader-elected) scheduling modes with job registration, execution history, retries with backoff, and an admin REST API with optional web UI.

What It Registers

ServiceDI KeyType
Job registrycron.registry*JobRegistry
Job executorcron.executor*Executor
Schedulercron.schedulerScheduler
Storagecron.storageStorage

All services are managed by Vessel. The scheduler starts during the extension's Start() phase.

Dependencies

  • Optional: database extension -- required when Storage is set to "database".
  • Optional: consensus extension -- required in "distributed" mode with LeaderElection enabled.

Quick Start

package main

import (
    "context"
    "fmt"

    "github.com/xraph/forge"
    "github.com/xraph/forge/extensions/cron"
)

func main() {
    app := forge.NewApp(forge.AppConfig{Name: "my-app", Version: "1.0.0"})

    ext := cron.NewExtension(
        cron.WithMode("simple"),
        cron.WithStorage("memory"),
        cron.WithMaxConcurrentJobs(10),
        cron.WithEnableAPI(true),
    )
    app.RegisterExtension(ext)

    // Register job handlers before starting
    registry := ext.GetRegistry()

    registry.Register("send-reports", func(ctx context.Context, job *cron.Job) error {
        fmt.Println("Generating and sending reports...")
        return nil
    })

    registry.Register("cleanup-temp", func(ctx context.Context, job *cron.Job) error {
        fmt.Println("Cleaning up temporary files...")
        return nil
    })

    // Create jobs
    ctx := context.Background()
    app.Start(ctx)
    defer app.Stop(ctx)

    ext.CreateJob(ctx, &cron.Job{
        Name:        "Daily Reports",
        Schedule:    "0 9 * * *",  // every day at 9 AM
        HandlerName: "send-reports",
        Enabled:     true,
        Timezone:    "America/New_York",
        MaxRetries:  3,
        Timeout:     5 * time.Minute,
    })

    ext.CreateJob(ctx, &cron.Job{
        Name:        "Hourly Cleanup",
        Schedule:    "0 * * * *",  // every hour
        HandlerName: "cleanup-temp",
        Enabled:     true,
    })
}

Job Management at Runtime

// Trigger a job manually (outside its schedule)
ext.TriggerJob(ctx, jobID)

// Update a job
ext.UpdateJob(ctx, jobID, &cron.Job{
    Schedule: "*/30 * * * *",  // change to every 30 minutes
    Enabled:  true,
})

// Delete a job
ext.DeleteJob(ctx, jobID)

// Get execution stats
stats, _ := ext.GetStats(ctx)
fmt.Printf("Total jobs: %d, Running: %d\n", stats.TotalJobs, stats.RunningJobs)

Handler Middleware

// Add middleware to handlers
registry.RegisterWithMiddleware("critical-job", myHandler,
    cron.CreateLoggingMiddleware(logger),
    cron.CreateTimeoutMiddleware(5*time.Minute),
    cron.CreatePanicRecoveryMiddleware(logger),
)

Key Concepts

  • Simple mode -- single-node scheduler using standard cron expressions.
  • Distributed mode -- uses the consensus extension for leader election. Only the leader executes jobs.
  • Job registry -- register handlers by name. Jobs reference handlers by name.
  • Executor -- runs handlers with concurrency limits, timeout enforcement, and retry logic.
  • Storage -- persist job definitions and history in memory or database backends.
  • Admin API -- REST API at /api/cron for managing jobs.

Detailed Pages

How is this guide?

On this page