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
pub type Message {
  Evaluate
}

Constructors

  • Evaluate

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/UTC is resolved through the OS timezone database, and an unknown name fails the plugin’s start (Elixir’s :timezone validation 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

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.

Search Document