schedule:run
* * * * * cd /srv/app && php mitosis schedule:run
Requires Clarity 1.5.0 or newer. That one line is the entire crontab, for
the life of the application. Every tick works out which registered jobs are due, claims each
one for the cluster, runs them, and records what happened. The schedule itself lives in
app/routes/cli.php — see Scheduler.
Put the line on every node. Claiming a job is an insert against a unique index, so three nodes give three chances a due job runs and no chance it runs three times.
Leave off the /dev/null redirect
A tick where nothing was due, or where every due job was already claimed by another node,
exits 0 in silence. That is on purpose: every line this command writes becomes a
cron mail, and a heartbeat that greets you sixty times an hour teaches you to filter it —
after which the one line that mattered is filtered too.
So the output is the alert, and the reflexive
> /dev/null 2>&1 throws the failures away along with the quiet. The
kernel writes errors to stdout like everything else, so there is nothing for
2>&1 to rescue either. Leave both off.
This departs from the always-print-success habit of cache:clear and the rest, deliberately. Four things get exactly one line each:
✓ sessions:prune: ran in 41ms.
✗ reports:build: failed after 1122ms — SQLSTATE[42S02]: Base table or view not found
ℹ sessions:prune: skipped, the previous run is still going.
✗ reports:build: 1 abandoned run reaped — started over 240 minutes ago and never reported an outcome.
The tick exits 1 if any job failed or any dead run was reaped, and 0
otherwise — including when it did nothing at all.
Options
--verbose narrate the whole tick: jobs that were not due, and slots another node claimed
--context select a database connection, as everywhere else
--verbose is for a human running the command by hand. Do not put it in the
crontab, or you have re-created the mailbox problem the silence exists to avoid.
A failing job does not stop the tick
Every job runs inside its own try/catch. The kernel catches a
Throwable, prints its message with no trace and abandons the process — so an
escaping exception would kill every later job in the same tick and reduce your diagnostic to
a single line. Instead the failure is recorded against its own run row, the message is
printed, and the next job runs.
If the table is missing
✗ Scheduler is not installed: the `scheduled_runs` table is missing, so no job can be claimed or recorded. Run `php mitosis schedule:install` once.
Checked up front and exits 1, rather than being discovered as a database error
once a minute for as long as the crontab entry outlives the install step. Run
schedule:install. A tick with no jobs registered at
all does not so much as open a connection.
What it guarantees, and what it doesn't
At most one run per job per minute, cluster-wide. Not at-least-once. A minute in which every node is down is a minute in which the job does not run, and no later tick makes it up: only the current minute is ever evaluated. A tick that starts more than 60 seconds late skips a minute entirely.
Expressions are read on the server's local clock, matching what the system cron itself reads — so every node in a cluster must be set to the same timezone, or they are running two different schedules.
Next steps
- Scheduler — registering jobs, expressions, and the staleness window.
- schedule:install — the table this command claims against.
- schedule:list — what is registered, and how each job's last run went.