Cron
Distributed cron scheduling with leader election and per-tenant support.
The cron package provides distributed cron scheduling. Only the cluster leader fires cron entries, guaranteeing at-most-once job enqueue even when multiple Dispatch instances are running.
Registering a cron
Use engine.RegisterCron at startup:
type ReportInput struct {
Format string `json:"format"`
}
var GenerateReport = job.NewDefinition("generate_report",
func(ctx context.Context, input ReportInput) error {
return generateDailyReport(input.Format)
},
)
// Run every day at 9 AM
engine.RegisterCron(ctx, eng, "daily-report", "0 9 * * *",
GenerateReport, ReportInput{Format: "pdf"})The cron entry is persisted in the store. If an entry with the same name already exists, ErrDuplicateCron is returned (unless UpsertOnConflict is used).
Schedule format
Dispatch uses standard 5-field cron expressions (via robfig/cron/v3):
┌───────────── minute (0–59)
│ ┌─────────── hour (0–23)
│ │ ┌───────── day of month (1–31)
│ │ │ ┌─────── month (1–12)
│ │ │ │ ┌───── day of week (0–6, Sunday=0)
│ │ │ │ │
* * * * *Common expressions:
| Expression | Meaning |
|---|---|
* * * * * | Every minute |
0 * * * * | Every hour |
0 9 * * 1-5 | Weekdays at 9 AM |
0 0 1 * * | First of each month at midnight |
@hourly | Every hour (alias) |
@daily | Every day at midnight (alias) |
Enable / Disable
Cron entries can be toggled at runtime:
POST /v1/crons/:cronId/enable
POST /v1/crons/:cronId/disableDisabled entries are skipped by the scheduler without being deleted.
Admin API
| Method | Path | Description |
|---|---|---|
GET | /v1/crons | List all cron entries |
GET | /v1/crons/:cronId | Get cron entry |
POST | /v1/crons/:cronId/enable | Enable |
POST | /v1/crons/:cronId/disable | Disable |
DELETE | /v1/crons/:cronId | Delete |
Extension hook
When a cron fires and a job is enqueued, the ext.CronFired hook is called:
type CronFired interface {
OnCronFired(ctx context.Context, entryName string, jobID id.JobID) error
}