Exit codes
Wire a shell job into Drumbeats with one extra line, using the exit code you already have.
One extra line at the end of a shell job:
your-job
curl -sf https://api.drumbeats.io/v1/ping/<monitor-id>/$?your-job
curl -sf https://api.drumbeats.io/v1/ping/<monitor-id>/$?$? holds the previous command's exit status. Drumbeats reads it as the event.
How codes map#
| Exit code | Recorded as | Effect on the monitor |
|---|---|---|
0 | success | Resolves any open incident, monitor flips UP |
1 through 255 | failure, with the exact code stored | Failure counter increments. Monitor flips DOWN at failure_tolerance |
| Anything else | Rejected with 400 and code: INVALID_EXIT_CODE | Nothing recorded |
Keeping the exact code matters during triage. 137 tells you the kernel killed the process, almost always out of memory. 124 is a timeout command firing. A custom exit 42 is your own code path. All three read as "failure" in the alert, and the number is what tells them apart.
Capture $? before anything else runs#
$? is overwritten by every command, including echo and the curl itself. Save it first:
your-job
EXIT=$?
# anything can happen here now
logger "job finished with $EXIT"
curl -sf https://api.drumbeats.io/v1/ping/<monitor-id>/$EXITyour-job
EXIT=$?
# anything can happen here now
logger "job finished with $EXIT"
curl -sf https://api.drumbeats.io/v1/ping/<monitor-id>/$EXITSkipping this is the most common way an exit-code integration silently reports the wrong thing. The naive your-job; logger ...; curl .../$? sends the exit status of logger, which is almost always 0, so every run looks successful.
Use ; not && in crontab#
0 2 * * * /usr/bin/backup.sh; \
curl -sf https://api.drumbeats.io/v1/ping/<monitor-id>/$?0 2 * * * /usr/bin/backup.sh; \
curl -sf https://api.drumbeats.io/v1/ping/<monitor-id>/$?With && the ping is skipped whenever the job fails, which is exactly when you want it. With ; the ping runs either way and carries the real code.
Compose with run_id#
Exit codes work alongside the named events. Send start at the top, finish with the code:
RUN_ID="job-$(uuidgen)"
API="https://api.drumbeats.io/v1/ping/<monitor-id>"
curl -sf "$API/start?run_id=$RUN_ID"
python worker.py
EXIT=$?
curl -sf "$API/${EXIT}?run_id=$RUN_ID"RUN_ID="job-$(uuidgen)"
API="https://api.drumbeats.io/v1/ping/<monitor-id>"
curl -sf "$API/start?run_id=$RUN_ID"
python worker.py
EXIT=$?
curl -sf "$API/${EXIT}?run_id=$RUN_ID"Always use -sf in cron#
-s silences curl's progress meter, which cron mails to root on every single run otherwise. -f makes curl exit non-zero on an HTTP error, so a 500 from the ping API does not read as success further down your chain.
When to use something else#
| Use exit codes | Use named events |
|---|---|
| You are wrapping one shell command | You need start and duration tracking |
$? is already sitting there | You want log pings between phases |
| Success and failure is the whole story | You want to attach stdout or an error message |
Both cost the same in beats. The exit-code form is a convenience, not a cheaper path. When you need more than a binary outcome, payloads and the named events give it to you.
What happens when it breaks#
An exit-code ping behaves exactly like the event it maps to. A non-zero code opens a FAILED incident once failure_tolerance is reached, pages every notification group on the monitor, and shows the numeric code on the incident timeline. A later 0 resolves it and sends the recovery message.
Next#
Ping API for the full event and error reference. Scheduled pings for the Cron and Heartbeat patterns most exit-code jobs use. Shell integration for production-grade scripts with retries and timeouts.