class Divider::Cron

Recurring jobs: entries of a five-field cron expression, in UTC, and a job class (with its arguments), which a worker enqueues when they are due (Worker.new(url, ..., cron: cron)).

cron = Divider::Cron.new([Divider::Cron.entry("*/5 * * * *", Divider::Job),
                          Divider::Cron.entry("@daily", Divider::Job)])
cron.due(Time.utc(2026, 11, 8, 0, 0)).size     # => 2
cron.due(Time.utc(2026, 11, 8, 0, 5)).size     # => 1
cron.due(Time.utc(2026, 11, 8, 0, 7)).size     # => 0

Fields: minute (0-59), hour (0-23), day of the month (1-31), month (1-12 or JAN-DEC), day of the week (0-7, 0 and 7 Sunday, or SUN-SAT); each a *, a number, a range a-b, a step */n or a-b/n, or a list of those separated by commas. When both the day of the month and the day of the week are restricted, a day matching either is due; a field that starts with * (*/2 too) counts as unrestricted there, as Vixie cron and cronie take it (0 0 */2 * MON: odd days that are Mondays). @yearly (@annually), @monthly, @weekly, @daily (@midnight) and @hourly stand for their usual expressions.

A worker checks every 15 seconds, by the database's clock, and enqueues each entry once per due minute however many workers check: a minute no worker checked (all of them stopped) is not made up afterwards.

/home/runner/work/divider/divider/src/cron.qz:26

Classes and modules

Constants

CLAIM: String

(One row per entry: the last minute it was enqueued for. Only the worker that moves it forward enqueues.)

/home/runner/work/divider/divider/src/cron.qz:76

MACROS: Hash[String, String]

/home/runner/work/divider/divider/src/cron.qz:141

NO_NAMES: Hash[String, Int]

/home/runner/work/divider/divider/src/cron.qz:143

MONTHS: Hash[String, Int]

/home/runner/work/divider/divider/src/cron.qz:144

WDAYS: Hash[String, Int]

/home/runner/work/divider/divider/src/cron.qz:146

Class methods

def self.new(entries: Array[Divider::Cron::Entry]) -> Divider::Cron

A schedule of entries.

/home/runner/work/divider/divider/src/cron.qz:32

def self.entry(expression: String, job: Type[Divider::Job], **args: Object) -> Divider::Cron::Entry

An entry: job enqueued, with args (its arguments as keywords, JSON-encoded now; checked when the job is decoded), at each minute expression matches. ArgumentError for an expression that does not parse.

/home/runner/work/divider/divider/src/cron.qz:42

def self.parse(expression: String) -> Divider::Cron::Schedule

The schedule of expression; ArgumentError when it does not parse.

/home/runner/work/divider/divider/src/cron.qz:81

Methods

def entries -> Array[Divider::Cron::Entry]

The entries.

/home/runner/work/divider/divider/src/cron.qz:36

def due(at: Time) -> Array[Divider::Cron::Entry]

The entries due at the minute of at (UTC; seconds ignored).

/home/runner/work/divider/divider/src/cron.qz:49