jonnify·redis /redis-patterns/time-delay-priority/schedulers/cron-vs-interval

R4.02.1 · Schedulers — dive 1

Naming "when next": cron vs interval.

A cron expression names a wall-clock calendar position; a fixed interval names a gap. Both reduce to one millisecond timestamp — the score the registry stores.

Grounding: echo/apps/echo_mq · repeat.ex (EchoMQ.Repeat, the interval form) · the every_ms field on the emq:{q}:repeat:<name> record hash.

Trace each cadence over a fixed clock. Select a rule to light its next-run marks and read the timestamp it produces.
08:45 09:15 09:45 09:00 09:05 09:20 09:35
readout · Select a cadence. A cron rule snaps to the next calendar slot; an interval marches the previous run forward by the gap.

Static verdicts (now = 08:50) — cron 0 9 * * * → next run 09:00, a wall-clock slot · interval every_ms 900000 → next run 09:05, the previous run plus 15 minutes. Both yield one future millisecond.

§1

The cron expression — a wall-clock slot

delayed-queue.md.txt · applied to recurrence

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. The rule answers which calendar slot, not how long a gap.

0 9 * * *
Minute 0, hour 9, any day — 09:00 daily.
next run
The earliest matching slot at or after now.
anchor
The wall clock; a slow run does not move the next slot.

A cron rule snaps the next run to a calendar position. The output is still a single future millisecond — the same kind of value an interval produces.

§2

The fixed interval — a gap

repeat.ex · every_ms

A fixed interval is a single number of milliseconds — every_ms: 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 :05, :20, :35 past whatever minute it started on, marching forward by the gap.

EchoMQ.Repeat is exactly this form: registration takes every_ms, the record hash stores it, and the pump advances the score by it each cycle. The two rules compute differently but produce the same kind of value — a future millisecond, the score ZADD'd into the registry against the registration's member. The registry does not separate a calendar match from a gap addition; it stores a sorted set of next-run times and the pump reads 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.

§3

In EchoMQ — every_ms on the record hash

repeat.ex · @register

EchoMQ.Repeat.register/6 takes a period in milliseconds and a payload template, and writes both the registry entry and a companion record hash in one inline Lua script. The script's first move is the idempotence probe; on a fresh name it writes the record then the registry score.

# @register (EchoMQ.Repeat) — KEYS[1] = the registry ZSET, KEYS[2] = the record hash.
if redis.call('EXISTS', KEYS[2]) == 1 then return 0 end           -- already registered
redis.call("HSET", KEYS[2], "every_ms", ARGV[2], "template", ARGV[3])   # the cadence on the hash
redis.call("ZADD", KEYS[1], tonumber(ARGV[4]), ARGV[1])              # the next run on the registry
# ARGV[2] every_ms · ARGV[3] template · ARGV[4] first-run millis · ARGV[1] registration name

KEYS[1] is emq:{q}:repeat (the registry sorted set), KEYS[2] is emq:{q}:repeat:<name> (the record hash). ARGV[2] is every_ms — the interval — and ARGV[3] is the payload template; ARGV[4] is the first run's millisecond, the registry score. The interval lives on the record hash; the registry sorted set stores only the computed next-run time.

Notes on ValkeyHSET writes the record fields in one command, and the registry ZADD scores the name by a single number, so the cadence and its next-run time live in two declared keys, both on the queue's slot — valkey.io/commands/hset.

/echomq/queue · the scheduling controls in depth

Where cron parsing lives

The cron-parser depth — how a calendar pattern plus a timezone resolves a slot across daylight-saving transitions — belongs to the scheduler subsystem the EchoMQ course covers. EchoMQ.Repeat ships the interval form; the Queue pillar teaches the controls that maintain the registry around it. See /echomq/queue.

the pattern

Name "when next" two ways — a wall-clock cron slot or a fixed gap. Both reduce to one future millisecond, the registry score.

its EchoMQ application

EchoMQ.Repeat is the interval form: register/6 stores every_ms on the record hash and the next-run time on emq:{q}:repeat.

A textbook delayed queue scores a job by one fixed fire-time. A scheduler computes that fire-time from a cadence rule each cycle; the registry stores the output, never the rule.

§4

Recap — two rules, one timestamp

next → R4.02.2

Cron names a calendar slot; an interval names a gap. Each computes a future millisecond, and that single number is the score the registry holds against the registration's member. EchoMQ.Repeat carries the interval rule as every_ms. The next dive keeps that single entry unique across boots — the EXISTS-guarded register.

§5

References

sources · related

Sources

Related in this course