Scheduled runs
Run a suite on a cron cadence, how the database-driven tick loop actually fires, and how to choose an interval worth paying for.
A suite that only runs when someone remembers to click it tells you about the code as it was the last time someone remembered. Schedules run it on a cadence, so a regression has a bounded lifetime — and so the trend charts have something to plot.
What a schedule is
| Field | Meaning |
|---|---|
| Name | What this schedule is for. |
| Cron expression | When it runs. |
| Suite | Which suite to run. Leave it empty to run every test in the project. |
| Environment | Pin the run to a named environment. Empty ⇒ the project's defaults. |
| Enabled | Off pauses the schedule without deleting it. |
Each schedule records its lastRunAt, nextRunAt, lastRunStatus
(passed / failed / error) and the suite run it produced, so the list doubles as
a health view: a schedule that has been failing for a week is visible without
opening anything.
Cron expressions
Standard five-field cron, parsed with cron-parser:
┌───── minute
│ ┌─── hour
│ │ ┌─ day of month
│ │ │ ┌─ month
│ │ │ │ ┌─ day of week
│ │ │ │ │
* * * * *| Expression | Runs |
|---|---|
0 * * * * | Every hour, on the hour |
*/15 * * * * | Every 15 minutes |
0 3 * * * | Every day at 03:00 |
0 6 * * 1-5 | Weekdays at 06:00 |
0 2 * * 1 | Mondays at 02:00 |
The expression is validated when you save it, so an unparseable schedule is rejected at the point you can still see what you typed rather than silently never firing.
How it fires
The server runs a tick loop that wakes on an interval, reads the schedules due from the database, and starts their runs. It is database-driven rather than in-process timers, which is what makes it survive a restart: a schedule due while the server was down fires on the next tick instead of being lost.
The tick interval is an admin-editable runtime setting, so it can be tuned without a redeploy.
Consequences worth knowing:
- Firing is "at or after" the cron time, not exactly on it. A schedule due at 03:00 starts on the first tick after 03:00.
- The cadence you can actually get is bounded by the tick interval. A
*/1 * * * *schedule cannot fire more often than the loop wakes. - Runs are subject to the plan's concurrency limit like any other run, so a burst of schedules due at the same minute queues rather than launching all at once.
Choosing a cadence
The useful question is how long you are willing for a regression to live undetected.
- On every push — that is CI's job, not a schedule. See CI integration.
- Hourly — for a critical flow (checkout, signup) where an hour of breakage is already expensive.
- Nightly — the default worth having. A full suite at 03:00 means every morning starts with a current answer, which is what the morning loop is built on.
- Weekly — for slow, broad or expensive suites: full device matrices, visual sweeps.
Scheduling everything hourly is a common instinct and usually a mistake: it burns concurrency, and a suite whose results nobody reads at 04:00 or 05:00 is not providing four times the value of one nightly run.
Notifications
A schedule that fails silently is a schedule that is not doing its job. Wire the results to Slack, email or a signed webhook so the failure arrives somewhere a person looks — otherwise the first you hear of it is when someone opens the dashboard.
Retention
Scheduled runs accumulate history faster than manual ones, which is the point (see Analytics) but also the storage cost. Run retention is bounded by the plan and by the platform policy, whichever is tighter, and artifacts are swept with the runs they belong to.
See also
- Suites & the run matrix — what a schedule runs
- Analytics & flaky-test detection — what the history is for
- The SDLC loop — where a nightly run fits in the week
- CI integration — per-change runs, the other half