schedule:install

php mitosis schedule:install
✓ Scheduler install complete: `scheduled_runs` created. Add one line to the system crontab and the schedule in app/routes/cli.php takes it from there:
    * * * * * cd /srv/app && php mitosis schedule:run

Requires Clarity 1.5.0 or newer. Creates the one table Scheduler needs — the run record that doubles as its cluster-wide lock. Run it once per database context, before you add the crontab line.

--context selects a connection, as everywhere else. An application running the scheduler on a second database installs the table there too.

Order does not have to be perfect

The crontab line added before this command produces a tick that exits 1 every minute and names schedule:install — loudly, rather than silently doing nothing. That is deliberate: a scheduler whose failure mode is silence is the worst kind.

Safe to run again

The table is skipped when it already exists, and nothing is changed:

✓ Scheduler is already installed: `scheduled_runs` was already present.

Guarded on whether the table is present rather than on CREATE TABLE IF NOT EXISTS, because that clause covers the table but not the indexes, which are emitted as separate statements MySQL has no IF NOT EXISTS for.

What it creates

One row per attempted run of one job: id (UUIDv7), job, due_at, state, started_at, finished_at, duration_ms, failure_reason, created_at, updated_at.

Three indexes, and the first of them is the whole design:

  • A unique index on (job, due_at) — the mutex. Two nodes whose crontabs fire in the same minute both try to insert the same pair, and exactly one succeeds. This is not there to dedupe anything; losing it does not degrade the scheduler, it silently doubles every job on every node.
  • (job, state) — the in-flight check and the reaper, both of which ask for one job's running rows.
  • due_at — pruning old run records.

job is 128 characters rather than the default 255 so the unique key stays comfortably inside MySQL's index-length limit under utf8mb4.

Why this is separate from setup

setup creates sessions and caches, the two tables Clarity itself owns and every app needs. Scheduling is opt-in, so an application that schedules nothing should not carry a table it never reads — the same decision checkout:install exists for.

A command rather than a shipped migration because Clarity's resources/ directory is excluded from the Composer distribution, so a migration file there would never reach anyone who installs the framework normally.

Where it fits

cp .env_example .env
php mitosis setup             # sessions + caches — always
php mitosis schedule:install  # only if you schedule work
php mitosis migrate           # your own app's migrations

# then, in the system crontab, on every node:
* * * * * cd /srv/app && php mitosis schedule:run

No > /dev/null 2>&1 on that line — see schedule:run for why.

Next steps

  • Scheduler — registering jobs, and what the claim guarantees.
  • schedule:run — the heartbeat this table records.