Scheduled pings
The ping patterns for jobs that run on a timetable, from the one-liner to the fully wired version.
The shape to reach for first:
API="https://api.drumbeats.io/v1/ping/<monitor-id>"
curl -sf "$API/start"
if /usr/bin/backup.sh; then
curl -sf "$API/success"
else
curl -sf "$API/failure"
fiAPI="https://api.drumbeats.io/v1/ping/<monitor-id>"
curl -sf "$API/start"
if /usr/bin/backup.sh; then
curl -sf "$API/success"
else
curl -sf "$API/failure"
fiTwo beats per run. You get duration tracking, immediate failure alerts, and hung-run detection.
These patterns apply to Cron and Heartbeat monitors, the two types that expect a ping on a timetable.
Start with one ping if that is all you need#
One ping at the end covers missed-run detection and costs 1 beat per run:
/usr/bin/backup.sh
curl -sf https://api.drumbeats.io/v1/ping/<monitor-id>/success/usr/bin/backup.sh
curl -sf https://api.drumbeats.io/v1/ping/<monitor-id>/successTwo gaps. A non-zero exit still sends success, because nothing checks the exit status. And under set -e, or if the process is killed, the curl never runs at all and Drumbeats hears nothing until the window closes. Either way you learn about the failure at the next missed window rather than when it happened.
Add the failure branch as soon as the job matters.
Write it inline in crontab#
No wrapper script needed:
0 2 * * * curl -sf https://api.drumbeats.io/v1/ping/<id>/start \
&& /usr/bin/backup.sh \
&& curl -sf https://api.drumbeats.io/v1/ping/<id>/success \
|| curl -sf https://api.drumbeats.io/v1/ping/<id>/failure0 2 * * * curl -sf https://api.drumbeats.io/v1/ping/<id>/start \
&& /usr/bin/backup.sh \
&& curl -sf https://api.drumbeats.io/v1/ping/<id>/success \
|| curl -sf https://api.drumbeats.io/v1/ping/<id>/failureAlways use curl -sf inside crontab. -s silences the progress meter, which cron would otherwise mail to root on every run. -f makes curl exit non-zero on an HTTP error, so a 500 from the ping API does not read as success to the rest of your chain.
Use the exit code when the branch is binary#
/usr/bin/backup.sh
curl -sf https://api.drumbeats.io/v1/ping/<monitor-id>/$?/usr/bin/backup.sh
curl -sf https://api.drumbeats.io/v1/ping/<monitor-id>/$?0 becomes success, anything else becomes failure, and the exact code is stored for triage. Exit codes has the full table and the concurrency-safe variants.
Send the error output with the failure#
The useful payload is the tail of stderr, not the whole log:
OUTPUT=$(run-job.sh 2>&1 | tail -n 100)
EXIT=$?
if [ $EXIT -eq 0 ]; then
curl -sf https://api.drumbeats.io/v1/ping/<monitor-id>/success
else
curl -sf -X POST https://api.drumbeats.io/v1/ping/<monitor-id>/failure \
-H "Content-Type: application/json" \
-d "$(jq -n --arg p "$OUTPUT" '{payload: $p}')"
fiOUTPUT=$(run-job.sh 2>&1 | tail -n 100)
EXIT=$?
if [ $EXIT -eq 0 ]; then
curl -sf https://api.drumbeats.io/v1/ping/<monitor-id>/success
else
curl -sf -X POST https://api.drumbeats.io/v1/ping/<monitor-id>/failure \
-H "Content-Type: application/json" \
-d "$(jq -n --arg p "$OUTPUT" '{payload: $p}')"
fiBuild the JSON with jq. A stack trace containing a quote or a newline breaks hand-rolled string interpolation, and it breaks on exactly the runs where you needed the payload.
Record which phase a job reached#
API="https://api.drumbeats.io/v1/ping/<monitor-id>"
curl -sf "$API/start"
pg_dump mydb > backup.sql \
|| { curl -sf "$API/failure"; exit 1; }
curl -sf -X POST "$API/log" -H "Content-Type: application/json" \
-d '{"payload":"DB dump complete (1.2 GB)"}'
gzip backup.sql \
|| { curl -sf "$API/failure"; exit 1; }
aws s3 cp backup.sql.gz s3://backups/ \
|| { curl -sf "$API/failure"; exit 1; }
curl -sf "$API/success"API="https://api.drumbeats.io/v1/ping/<monitor-id>"
curl -sf "$API/start"
pg_dump mydb > backup.sql \
|| { curl -sf "$API/failure"; exit 1; }
curl -sf -X POST "$API/log" -H "Content-Type: application/json" \
-d '{"payload":"DB dump complete (1.2 GB)"}'
gzip backup.sql \
|| { curl -sf "$API/failure"; exit 1; }
aws s3 cp backup.sql.gz s3://backups/ \
|| { curl -sf "$API/failure"; exit 1; }
curl -sf "$API/success"Each log costs a beat. Use them on jobs where knowing the phase changes what you do next.
What happens when it breaks#
| What Drumbeats sees | Result |
|---|---|
success | Monitor flips UP, any open incident resolves |
failure | Failure counter increments. Monitor flips DOWN at failure_tolerance |
start with no finish inside max_duration_seconds | Hung run, counted as a failure |
log | Stored on the timeline. No status change |
Nothing by the expected time plus grace_period_seconds | MISSED incident opens |
Finish slower than max_duration_seconds | DURATION_HIGH warning. The monitor stays UP |
Finish faster than min_duration_seconds | DURATION_LOW warning. The monitor stays UP |
How you get alerted#
The incident pages every notification group on the monitor, and all channels fire in parallel. The next success resolves it and sends a recovery message carrying the outage duration.
Do not let the ping break the job#
If a ping outage should never fail the underlying work, swallow the error:
The real work already happened. Losing one ping costs you a data point. Letting a monitoring call abort a backup costs you the backup. Always pair || true with --max-time so a hung connection cannot stall the job either.
Next#
Cron monitors and heartbeat monitors for what the monitor does with these pings. Payloads for size limits and truncation. Production hardening for retries and timeouts.