mule/plugins/cron
The Cron plugin: enqueue jobs on a schedule. A Stager-shaped actor that
evaluates its crontab once per minute (aligned to the :00 boundary) and
inserts a job for every entry whose minute matches.
Faithful to Oban: cron jobs carry no uniqueness by default — duplicate
prevention is structural (one leader, evaluated once per minute); a
per-entry job.Unique option adds it. The leader check reads
config.peer.is_leader() (a pure cell lookup): in a cluster the Postgres
lease peer makes exactly one node the leader; single-node / in-memory
uses peer.always_leader. Expressions are parsed by
mule/cron/expression (the Oban.Cron.Expression port — nicknames,
named ranges, validated bounds). Evaluation runs in the plugin’s
timezone (default Etc/UTC; anything else resolves through the OS
timezone database via tzif, cron.ex’s DateTime.now(timezone)). No
catch-up: a minute missed while the node is down is skipped. @reboot
entries fire on the FIRST evaluation this node runs as leader and are
then dropped from its crontab (cron.ex discard_reboots — a non-leader
keeps them, so a later leadership handoff still runs them once).
Types
One scheduled entry: a parsed cron expression and the job to enqueue when
it fires. Build with entry or entry_with, which capture the worker’s
name and the encoded args (so the crontab can hold entries with differing
arg types).
pub opaque type CronEntry
Plugin-level options (cron.ex’s :timezone).
pub type Option {
Timezone(timezone: String)
}
Constructors
-
Timezone(timezone: String)The IANA timezone expressions evaluate in. Anything other than the default
Etc/UTCis resolved through the OS timezone database, and an unknown name fails the plugin’s start (Elixir’s:timezonevalidation raises at init).
pub type State {
State(
config: config.Config,
crontab: List(CronEntry),
local_clock: cron.LocalClock,
clock: fn() -> timestamp.Timestamp,
self_subject: process.Subject(Message),
)
}
Constructors
-
State( config: config.Config, crontab: List(CronEntry), local_clock: cron.LocalClock, clock: fn() -> timestamp.Timestamp, self_subject: process.Subject(Message), )
Values
pub fn entry(
expression expression: String,
worker worker: worker.Worker(a),
args args: a,
) -> Result(CronEntry, String)
Build a crontab entry from a cron string and a typed worker + args, or return an error describing an unparseable expression.
pub fn entry_with(
expression expression_input: String,
worker worker: worker.Worker(a),
args args: a,
options options: List(job.Option),
) -> Result(CronEntry, String)
entry with per-entry job.Options (cron.ex’s
{expr, worker, options} form): queue, priority, tags, max_attempts,
unique, … applied over the worker’s own defaults exactly like
mule.insert_with. job.Meta is rejected — the plugin owns the job meta
(cron / cron_expr / cron_name / cron_tz); Elixir merges instead
(parity §9).
pub fn plugin(crontab crontab: List(CronEntry)) -> plugin.Plugin
Package a crontab as a runtime Plugin for MuleSpec.plugins, evaluated
in UTC. The crontab is captured here; Config (engine + notifier) is
supplied by mule.start when the supervisor builds the child.
pub fn plugin_with(
crontab crontab: List(CronEntry),
options options: List(Option),
) -> plugin.Plugin
plugin with plugin-level options (Timezone).
pub fn start(
config config: config.Config,
crontab crontab: List(CronEntry),
timezone timezone: String,
) -> Result(
actor.Started(process.Subject(Message)),
actor.StartError,
)
pub fn start_with_clock(
config config: config.Config,
crontab crontab: List(CronEntry),
clock clock: fn() -> timestamp.Timestamp,
) -> Result(
actor.Started(process.Subject(Message)),
actor.StartError,
)
Start with an injected clock — used by tests to drive evaluation at a chosen instant rather than waiting for a real minute boundary.
pub fn start_with_clock_in_timezone(
config config: config.Config,
crontab crontab: List(CronEntry),
timezone timezone: String,
clock clock: fn() -> timestamp.Timestamp,
) -> Result(
actor.Started(process.Subject(Message)),
actor.StartError,
)
start_with_clock in a non-UTC timezone.