-
Notifications
You must be signed in to change notification settings - Fork 0
Hashed Schedules
H * * * * runs a job once an hour, at a minute cronstable picks by hashing the job's name. Every job that uses H lands on its own stable slot, so a fleet of hourly jobs spreads across the hour instead of stampeding at :00. The syntax is Jenkins-style and drops into any field except the year.
jobs:
- name: refresh-cache
command: ./refresh
schedule: "H * * * *" # this job's own minute, every hour
- name: nightly-report
command: ./report
schedule: "H H * * *" # a stable minute AND hour, once a dayRandom jitter also spreads load, but it destroys the question a monitoring product must answer: "was this run late?" A randomly jittered job has no fixed expected time, so lateness is undefined. A hashed slot is a pure function of the job name: it survives restarts, config reloads, and re-deploys, and it is identical on every replica of the same config. The job fires at the same minute today, tomorrow, and on the standby node, so late-run detection, scheduled_in countdowns, and the dashboards' next-fire previews all keep working.
The cost of that predictability: renaming a job re-hashes its slots (the name is the seed), and in a classic crontab file, where names embed the line number, inserting a line above an H entry moves it the same way.
| Form | Meaning |
|---|---|
H |
One hashed value from the field's whole range. In day-of-month, every rangeless H form (bare H and H/n alike) hashes over 1 to 28, so a short month is never silently skipped; write H(1-31) to opt back in to the full range. |
H(a-b) |
One hashed value from the numeric range a to b (H(0-29) picks a first-half-hour minute). |
H/n |
Every n, starting at a hashed offset: a minute H/15 fires four times an hour at p, p+15, p+30, p+45 for this job's own phase p. In day-of-month the steps stay within 1 to 28, like bare H. |
H(a-b)/n |
Every n within a to b, phase hashed. The step must not exceed the range's span. |
Details that keep the behavior boring and predictable:
- The hash is a SHA-256 of the job name, salted per field, so
H H * * *picks an uncorrelated minute and hour rather than the same residue twice. It does not depend on Python'shash()and is identical across processes, hosts, and versions; the concrete slots are pinned by tests. - Because the moduli divide each other, a job's bare
Hminute and itsH/15phase agree (43and13,28,43,58for the same name), so tightening or loosening a job's cadence keeps it on familiar minutes. -
Hresolves at config load, before scheduling. Everything downstream (matching, next-fire search, semantic schedule equality) sees plain values, andH * * * *compares equal to the43 * * * *it resolved to. - A minute
H/7gets the sameuneven-steplint warning as*/7: seven does not divide sixty, so one interval at the wrap is short.
The original H spelling is what you configured, so it is what the surfaces display; the resolved values ride along everywhere they matter:
- The schedule linter attaches a
hashed-slotnote to everyHjob naming the exact expression it resolved to. -
GET /jobsaddsschedule_resolvednext toscheduleforHjobs, andGET /schedule/previewtakes aseedparameter (a job name, real or prospective) so sandboxes can resolveHexpressions; see HTTP API. - The web dashboard's job drawer shows "
H * * * *(H resolves to9 * * * *)", and its previews and collision analysis compute from the resolved form. - The job-set fingerprint hashes the schedule as written, so an
Hschedule fingerprints asH; identical configs still agree across replicas because the resolution is deterministic.
Schedule Pressure shows the problem (37 jobs fire at :00); H is the remedy you can apply per job without anyone coordinating slot assignments by hand. Suggest a Slot is the middle path when you want a concrete, explicit minute instead.
This wiki documents cronstable. See the README and the changelog.
cronstable is a fork of gjcarneiro/yacron.
cronstable™ and the cronstable logo are trademarks of the cronstable authors; the code is MIT-licensed (see TRADEMARKS.md and LICENSE).
- Getting Started
- Configuration
- Job Behavior
- Integrations
- Reference and Development