Heartbeats
Understand passive checks: how heartbeats monitor cron jobs, background workers, and scheduled tasks.
What is a heartbeat?
A heartbeat is a passive check. Instead of the platform actively probing your service, your service probes the platform. At the end of each scheduled job run, your script sends an HTTP POST to a unique ping URL. The platform records the ping and resets the timer. If no ping arrives within interval + grace_period, an alert opens.
This inverted model is ideal for monitoring things that cannot be reached from outside your network: cron jobs, internal workers, batch processes, or any task that runs on a schedule.
How the timing works
Heartbeat timing: each ping resets the clock; silence past interval + grace opens an alert
The grace period is an intentional buffer to absorb jobs with variable runtime. Set it to at least 20–30% of the expected runtime variance.
A heartbeat is marked down (and an alert opens) when any of these holds:
- the last ping is older than
interval + grace_period, or - it was never pinged and is older than twice its interval, or
- a cron-scheduled heartbeat missed its scheduled time plus grace.
Alerts are idempotent. While one alert is open, another missed heartbeat does not open a duplicate.
Heartbeat statuses
interval + grace_period.Only ping the platform when your job succeeds. If the job exits with an error, skip the ping. The platform will open an alert when the window expires, giving you an accurate alert for job failures.
Ping URL format
Each heartbeat gets a unique URL of the form:
POST https://api.howlops.com/api/v1/hb/{slug}
The {slug} is the URL-safe identifier shown on the heartbeat detail page. The endpoint is public and requires no authentication (the secret is the unguessable slug itself). POST is recommended, but GET and HEAD are also accepted, which helps with uptime tools or browsers that can only issue a GET. The response body and any request body are ignored; only the URL matters. A 200 OK response confirms the ping was recorded.
Treat the ping URL as a secret. If it is exposed, choose Rotate URL on the heartbeat detail page and update the job. The existing history stays attached to the heartbeat and the old slug stops working immediately.
Runbook link
A heartbeat can carry an optional runbook_url (must start with https://) pointing at the
response procedure for the job it watches — the same field monitors have. Set or clear it
through the API (POST /api/v1/heartbeats or PATCH /api/v1/heartbeats/{id}); there is no
in-app field for it yet. See the REST API overview for authentication.
History retention
Heartbeat ping history follows the workspace's current retention entitlement. The heartbeat detail page shows a recent timeline and a ping log; it does not render the full retention window at once. See the pricing page for the current plan comparison.
Common patterns
Job success only
/path/to/job.sh && curl -sS -X POST "$PING_URL"
Separate success from failure
if /path/to/job.sh; then
curl -sS -X POST "$PING_URL"
else
echo "Job failed, skipping heartbeat ping" >&2
exit 1
fi
Python context manager
import contextlib, requests
@contextlib.contextmanager
def heartbeat(ping_url: str):
yield
requests.post(ping_url, timeout=5)
with heartbeat("$PING_URL"):
run_my_job()
Was this page helpful?