jonnifyredis

R4.02.1 · dive 1

Cron vs interval

Two ways to name "when next": a cron expression names a wall-clock calendar slot, a fixed interval names a gap. Both reduce to one millisecond — the registry's score.

A cron expression like 0 9 * * * matches a calendar position — 09:00 every day — and the next run is the next slot at or after now. An interval like every: 900000 ms names a gap and the next run is the previous run plus the gap. Compute the next run each way over a fixed clock on the right, and read the two next-run timestamps.

Next run from a fixed now · cron 0 9 * * * vs interval every 15 min

08:48
clock — next run from a fixed cadence now 08:48 cron 0 9 * * * → next run 09:00:00

The cron expression — a wall-clock slot

A cron expression is five fields — minute, hour, day-of-month, month, day-of-week. 0 9 * * * reads "minute 0, hour 9, any day, any month, any weekday" — 09:00 every day. The next run is the earliest calendar slot at or after the current time that the expression matches.

Cron anchors to the wall clock, so a daily-at-09:00 schedule fires at 09:00 regardless of when it last ran or how long the last run took. Move now across 09:00 in the figure and the cron next-run snaps to today's 09:00 while now is before it, then to the next day's 09:00 once now has passed it.

A cron expression names a calendar slot; the next run is the earliest matching slot at or after now, anchored to the wall clock.

The fixed interval — a gap

A fixed interval is a single number of milliseconds — every: 900000 is fifteen minutes. The next run is the previous run plus the gap. An interval anchors to its own previous run rather than to the calendar, so an interval-every-15-min schedule fires at :00, :15, :30, :45 past whatever minute it started on, marching forward by the gap.

Switch the cadence to the interval in the figure: the next-run marks step every fifteen minutes, and the next run is the first mark at or after now — not a calendar position, but the next gap boundary.

A fixed interval names a gap; the next run is the previous run plus the gap, anchored to the prior run rather than the calendar.

Both reduce to one timestamp

The two rules compute differently but produce the same kind of value: a future millisecond. That single number is the score ZADD'd into the registry against the scheduler's member. The registry does not record whether the next run came from a calendar match or a gap addition — it stores a sorted set of next-run times and pops the earliest.

Naming the cadence is the only place the two rules differ; downstream, a cron schedule and an interval schedule are the same one-entry-scored-by-next-run row. The score is the meaning; the cadence is the rule that produced it.

cron
0 9 * * * — a calendar slot; next run = the earliest matching slot at or after now.
interval
every: 900000 — a gap; next run = previous run + gap.
score
The computed next-run millisecond, written with ZADD to the :repeat registry — the same shape for both rules.

Same registry row · either rule produces one ZADD with one next-run score

emq:{queue}:repeat (ZSET) — the registry row sched:reports → score = next-run millis options hash repeatKey:sched:reports — pattern "0 9 * * *" one row, scored by next-run — the rule is on the hash

Cron and interval are two rules with one output: a future millisecond, stored as the registry's score; downstream the two schedules are identical rows, differing only in the cadence field on the options hash.

In EchoMQ — pattern and every on the options hash

The store function storeRepeatableJob(repeatKey, customKey, nextMillis, rawOpts) in addRepeatableJob-2.lua is given nextMillis already computed by the caller, and it records two things: the next-run time on the registry sorted set, and the cadence on the companion hash.

-- addRepeatableJob-2.lua · storeRepeatableJob (real)
ZADD repeatKey nextMillis customKey            -- the next run, on the registry ZSET
HMSET repeatKey..":"..customKey            -- the cadence, on a separate hash
  "name" opts.name "pattern" opts.pattern "every" opts.every

The pattern field holds the cron expression; the every field holds the interval. EchoMQ stores both so a schedule can be defined either way; only one is set per scheduler. The registry sorted set carries only the computed nextMillis; the rule that produced it lives in the companion hash, alongside an optional tz.

the pattern

A scheduler needs a rule for "when next." Cron names a calendar slot; an interval names a gap. Both reduce to one future millisecond — the score the registry stores, identical in shape for either rule.

in EchoMQ

storeRepeatableJob writes the computed nextMillis to the :repeat ZSET with ZADD and the cadence fields (pattern, every, tz) to a companion HMSET hash — the rule on the hash, the next run on the registry.

The pattern says cron and interval are two rules with one timestamp output; in EchoMQ the rule lives on the companion HMSET hash and the computed next run on the :repeat ZSET.

Door · not depth The cron parser itself — how pattern plus tz resolves a calendar slot across daylight-saving transitions, and how a missed slot is reconciled — belongs to the scheduler subsystem the dedicated EchoMQ course covers at E6 · Lifecycle controls. This dive teaches the two cadence shapes and the single timestamp they both become; that course teaches the parser that computes it.

References

The cron expression as a calendar cadence, the command that writes the computed next run, the sorted set both cadences feed, and the queue protocol whose cadence options EchoMQ ports.

Sources

Related in this course