/start, /fail and duration
One ping says "I am alive". Three signals tell you when the job started, how it ended and how long it took.
Ping URL suffixes
| Address | Meaning | Status after |
|---|---|---|
/<uuid> | success | up |
/<uuid>/start | the job started | unchanged |
/<uuid>/fail | explicit failure | down immediately |
/<uuid>/<code> | exit status 0–255 | 0 is up, anything else is down |
/<uuid>/log | journal entry | unchanged |
A POST body (up to 100 KB) is stored in the ping log — a handy place for the tail of a log, so an incident can be triaged without logging into the server.
A start → success pair is what gives you duration
The execution duration chart on the check page is built
only from pairs: /start,
then a success or an exit code. The gap between them is the
runtime.
The consequence worth knowing. If you only send the
success ping and never /start,
the check works perfectly well — statuses, alerts and uptime
are all there — but the duration chart stays empty: there is
nothing to subtract. Milliseconds only exist for runs that
had a start.
# no duration: the service knows it ran, not how long it took /usr/local/bin/backup.sh && curl -fsS -m 10 "$PING" # with duration curl -fsS -m 10 "$PING/start" /usr/local/bin/backup.sh curl -fsS -m 10 "$PING/$?"
Pairs are matched in arrival order. If the job can run in several instances at once, durations blend together — such cases deserve separate checks.
Failing without the wait
The usual route to down is silence: deadline, then grace, then the alert. An explicit failure signal skips all of it — the check drops the moment the ping lands.
/fail— "the job reported an error";/<code>— the exit status:0counts as success, anything else drops the check. The alert reason reads "non-zero exit status".
The second form is friendlier in a shell: the exit code of
the last command already sits in $?,
no branching required. In systemd the same role is played by
$EXIT_STATUS inside
ExecStopPost — see the
snippets.
signal() { curl -fsS -m 10 --retry 3 -o /dev/null "$PING$1" || true; }
signal /start
/usr/local/bin/backup.sh
signal "/$?" A journal entry without a status change
/log writes a line into the
journal without touching the status or the deadline. Useful
for milestones inside a long run: "exported 10,000 rows",
"switched to the fallback source".
A first ping can create the check
Creating checks by hand is optional. Ping by slug — a
readable name instead of a UUID — with
?create=1, and the check appears
on first contact. Handy when jobs are rolled out by a deploy
and you do not know up front how many there will be.
https://ping.cronalive.com/<ping-key>/<slug>?create=1
ping-key is the project key
(Projects → Ping key in the dashboard), shared by all
of its checks; slug is the job
name in lower case, for example
etl-run. The schedule of the new
check comes from the query parameters:
| Parameter | Value |
|---|---|
period | period in seconds, 60–31536000 |
grace | grace in seconds, 30–2592000 |
cron | a cron expression instead of a period |
tz | time zone for cron, UTC by default |
tags | comma-separated tags, up to 20 × 64 characters |
# a plain period curl "https://ping.cronalive.com/<ping-key>/etl-run?create=1&period=3600&grace=300" # a cron expression with a time zone (plus signs instead of spaces) curl "https://ping.cronalive.com/<ping-key>/backup?create=1&cron=30+3+*+*+*&tz=Europe/Berlin" # tags for grouping on the dashboard — comma-separated curl "https://ping.cronalive.com/<ping-key>/etl-run?create=1&period=3600&tags=etl,prod"
Rules worth knowing in advance:
- the call is idempotent: for an existing check
create=1and the schedule parameters are ignored — the ping simply counts. Change the schedule in the dashboard or through the API; - signal suffixes work here too, but they belong in the path, ahead of the query:
/<ping-key>/etl-run/start?create=1; - with no parameters the project defaults apply (Projects → Auto-provisioning);
- a grace below 30 seconds is raised to 30, silently, and the check is still created. Schedulers start jobs with a few seconds of jitter — waiting for CPU, for the network, surviving a daemon restart — and a grace of a few seconds turns that jitter into a stream of false down/up alerts. Refusing the ping instead would leave the job with no monitoring at all, and nobody would find out, because finding out was the monitoring's job. In the dashboard and the API, where a human is at the screen, the same value is rejected with an explicit error rather than adjusted;
- tags are corrected, never rejected: blanks are dropped, anything over 64 characters is truncated, anything past the twentieth tag is discarded — and the check is created anyway. A label for grouping on the dashboard is not worth failing a ping over, let alone leaving a job unmonitored;
- invalid parameters give 400, an exhausted plan check limit gives 403, disabled auto-provisioning gives 404. A broken
cronor an unknowntzis still a 400 — unlike a too-small grace, there is nothing sensible to clamp them to, and guessing would create a check that waits for pings at the wrong time; - the ping key grants no API access and does not reveal other checks' UUIDs, but it can create checks in the project — treat it as a secret and rotate it if it leaks.
Laravel: the schedule fills itself in
The cronalive/laravel package reads the schedule off the scheduled task and sends it with the first ping, so you never retype it — and the check cannot drift away from the code:
// routes/console.php $schedule->command('etl:run') ->everyFiveMinutes() ->pingCronaliveSlug('etl-run'); // the first ping goes out as: // /<ping-key>/etl-run/start?create=1&cron=*%2F5+*+*+*+*&tz=UTC // grace and tags — named arguments, the second positional one is $create: $schedule->command('backup:run') ->dailyAt('03:30')->timezone('Europe/Berlin') ->pingCronaliveSlug('backup', graceSec: 1800, tags: ['backups', 'prod']);
- the time zone is the task's own if it sets one, otherwise your
app.timezone; - sub-minute tasks (
everyThirtySeconds()) travel asperiod=60— the shortest period the service accepts, so such a job is monitored as «pings at least once a minute»; - the parameters ride on all three signals, because whichever arrives first is the one that creates the check.
See also
- Snippets — all three signals in ready-made code;
- Cron job monitoring — step-by-step setup from scratch;
- Statuses and lifecycle — grace, instant down, reset;
- Ping reliability — timeouts, retries and limits.