Status · Guides
Watch a cron job
A heartbeat is an address your job calls each time it runs. When the call doesn't come in time, or the job says it failed, the heartbeat is down.
Add a heartbeat
On the project's Heartbeats page, choose Add heartbeat. You need the editor or admin role.
| Field | What it does |
|---|---|
| Name | As your team says it: "Nightly backup", "Invoice import". |
| Environment | Which of the project's environments its job runs in, guessed from the name. |
| A ping every (minutes) | How often the job runs: 5, 60, or 1440 for daily, up to 10,080 (a week). Or a schedule, below. |
| Grace (minutes) | How late a ping may be before it's down, 0 to 1,440. 1 by default. Give a job that runs for a while the time it takes. |
| Or on a schedule (cron) | Five fields, as in a crontab: 0 3 * * * is 03:00 every day. See Jobs on a schedule. |
| Its time zone | The schedule's clock, such as Europe/Helsinki or UTC. |
Choose Add heartbeat. Its page then shows its ping address and the lines to copy for a crontab and for Laravel's scheduler, already filled in with that address. The address looks like this:
https://services.my-beast.com/status/ping/abc123def456ghi789jkl012A new heartbeat is Waiting until its first ping, and nothing is told about a job that hasn't started yet. If no ping comes within a day of adding it, the alert channels hear of it once.
The address is the heartbeat
Ping it from a crontab
Put the ping after the job's own command, joined with &&, so it's only called when the job succeeded:
*/5 * * * * /usr/local/bin/backup.sh && curl -fsS -m 10 https://services.my-beast.com/status/ping/abc123def456ghi789jkl012-f makes curl fail on an error answer, -sS keeps it quiet unless something goes wrong, and -m 10 gives up after 10 seconds, so a slow network never holds your job. A ping can be a GET or a POST. It answers 200 with OK, or 404 for an address that isn't a heartbeat.
Ping it from Laravel's scheduler
Laravel's scheduler pings for you. The heartbeat's page gives this line with its own address and, where Laravel has a word for it, the frequency you set:
// routes/console.php
use Illuminate\Support\Facades\Schedule;
Schedule::command('backup:run')->everyFiveMinutes()
->pingBefore('https://services.my-beast.com/status/ping/abc123def456ghi789jkl012/start')
->pingOnSuccess('https://services.my-beast.com/status/ping/abc123def456ghi789jkl012')
->pingOnFailure('https://services.my-beast.com/status/ping/abc123def456ghi789jkl012/fail');pingBefore marks the start of the run, pingOnSuccess its success, and pingOnFailure a failure, which is a down at once.
Report the whole run
A heartbeat can hear more than "it ran". Add a word after the address:
| Call | What it says |
|---|---|
…/start | The job started. Its run is timed, and a run that hasn't ended within the heartbeat's period is down. |
the plain address, or …/0 | It succeeded. The heartbeat is up, and its time starts again. |
…/fail | It failed. The heartbeat is down at once: "Its job said it failed". |
…/<exit code> | It ended with this code. Anything but 0 is down at once: "Its job ended with exit code 2". |
Send the job's output as the body of a POST, and its last 10 KB are kept with the ping and shown on the heartbeat's page, so a failure says why. This line does all of it: the start, then the exit code ($?) with the output.
0 3 * * * curl -fsS -m 10 https://services.my-beast.com/status/ping/abc123def456ghi789jkl012/start; /usr/local/bin/backup.sh > /tmp/backup.log 2>&1; curl -fsS -m 10 --data-binary @/tmp/backup.log https://services.my-beast.com/status/ping/abc123def456ghi789jkl012/$?Output is kept as it is
Jobs on a schedule
A job that runs at set times, not every so many minutes, fits a schedule better: 0 3 * * * in Europe/Helsinki for a backup at 03:00 Helsinki time. Each run is due by its own time plus the grace, so a run that comes late never moves the next one's deadline. The heartbeat's page says the schedule in words, such as "Every day at 03:00 (Helsinki)".
Left blank, the time zone is Helsinki's. A schedule Status can't read, or a zone it doesn't know, is refused when you save.
When it's down
- Late. No ping by the time it was due plus the grace: "No ping since 14:02 EET, expected every 5 min (1 min grace)". The downtime starts when the grace ran out.
- Failed. The job called
/failor an exit code other than 0. - Never finished. It called
/start, and no ping came within its period.
The next successful ping makes it up again. Each heartbeat takes up to 60 pings a minute; more are refused with 429, so a job in a loop can't flood it. A paused heartbeat still answers pings, but isn't watched until you resume it.
How a down reaches people is the same as for an HTTP check: see Choose who's told.