title: "Alert on a daily cron failure" description: "Wire a nightly cron to BoxWatch so a failed run — or no run at all — pages you within the hour." last_updated: "2026-05-24"
Alert on a daily cron failure
You have a database backup that runs at 3 AM. Two failure modes matter:
- It ran and failed —
pg_dumperrored, disk filled, S3 timed out. - It didn't run at all — cron was disabled during a deploy, the VM was rebooted, the user got deleted.
Both are silent on the box itself. The job either exits non-zero into the void or simply doesn't fire. This recipe wires that 3 AM cron so either mode lands in Slack within an hour.
What you'll end up with
- One BoxWatch cron check called
nightly-db-backup. - A modified crontab that pings BoxWatch on start, success, and failure.
- An email alert by default; Slack on top if you want it.
Step 1: create the cron check in BoxWatch
- Dashboard → Checks → New check.
- Name:
nightly-db-backup. - Interval: 24 hours.
- Grace period: 60 minutes — your job can be up to an hour late before BoxWatch panics.
- Linked server (optional): pick the DB host. Linking lets the check inherit that server's maintenance windows.
- Max duration (optional): if your backup takes ~10 minutes, set 30 minutes here and you'll also get an alert when the job runs but won't finish.
- Alert types: enable Missed and Fail. Optionally enable Stuck if you set a max duration.
- Create.
You'll land on the detail page showing three ping URLs:
https://api.boxwatch.app/ping/abc123-...— successhttps://api.boxwatch.app/ping/abc123-.../start— starthttps://api.boxwatch.app/ping/abc123-.../fail— fail
The slug is a UUIDv4. It's secret, but it's not a password — there's no auth header. Anyone with the URL can ping it. Don't paste it into a public repo. See Cron checks for the full URL semantics.
Step 2: wrap your cron with start/success/fail pings
Your current crontab line probably looks like this:
# /etc/cron.d/nightly-backup
0 3 * * * root /opt/backup.shChange it to:
# /etc/cron.d/nightly-backup
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
0 3 * * * root curl -fsS https://api.boxwatch.app/ping/abc123-.../start \
&& /opt/backup.sh \
&& curl -fsS https://api.boxwatch.app/ping/abc123-... \
|| curl -fsS https://api.boxwatch.app/ping/abc123-.../fail/$?What each line does:
PATH=...— cron's defaultPATHis famously restrictive (/usr/bin:/binon most distros). If yourcurlis at/usr/bin/curlyou're fine, but adding an explicitPATH=line at the top of the crontab saves a future headache.curl ... /start— tells BoxWatch the job has begun. Enables duration tracking and stuck-job alerts.&& /opt/backup.sh— runs the backup only if the start ping succeeded. If BoxWatch is unreachable, the job still runs (because that's almost certainly what you want), but only because of the||branch below.&& curl ... /success— fires only whenbackup.shexits 0.|| curl ... /fail/$?— fires when anything before this exited non-zero.$?is the previous command's exit code. The catch: this||runs ifbackup.shfailed or if the start ping failed. In practice that's fine — you want an alert either way.
If you want a stricter wrapping that distinguishes "start ping failed" from "backup failed," push the logic into a wrapper script (/opt/backup-wrapped.sh) and call that from cron. Easier to read, easier to test, easier to add log capture.
Step 3: verify
Don't wait for 3 AM. Run the wrapped command by hand:
curl -fsS https://api.boxwatch.app/ping/abc123-.../start
/opt/backup.sh
curl -fsS https://api.boxwatch.app/ping/abc123-...Open the cron check's dashboard page. You should see:
- Last ping: just now
- Last success: just now
- Status: up
If the dashboard still says "no pings yet" after 30 seconds, your curl isn't reaching BoxWatch. Check curl -v output for HTTP 200 OK and {"ok": true}.
Step 4: connect a notification channel
Email alerts are on by default — they go to your account email. To add Slack:
- Dashboard → Account → Notifications.
- Paste your Slack incoming-webhook URL.
- Save.
From the next state transition forward, alerts post to Slack as well as email. See Slack alerts for the message format.
Anti-flapping behavior
BoxWatch only alerts on state transitions. If your job ran successfully yesterday and successfully today, no alert. If today's run failed, you get one alert — then BoxWatch goes quiet until either it succeeds again (recovery alert, if enabled) or it fails again tomorrow (you don't get re-paged on the same incident).
A one-off blip — single failed ping followed by a successful one a minute later — doesn't double-alert.
Common gotchas
- Cron's restricted PATH breaks
curl. Either use the full path (/usr/bin/curl) or setPATH=at the top of the crontab, as shown above. set -escripts don't always exit non-zero. Backup scripts that pipe through| trueor trap errors can return 0 even on partial failure. Test the failure case explicitly:false; echo "exit was $?".- Silent-on-success scripts. If your script suppresses output, your
&& curl ... /successstill fires correctly because shell exit codes don't depend on stdout. You're fine. - Cron's email-on-output. If you don't want cron emailing you every time the start ping prints a
{"ok":true}blob, add> /dev/nullafter eachcurl, or useMAILTO=""at the top of the crontab.
For the full set of cron-check alert types (missed, fail, stuck, long), see Cron checks.