Concepts

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

DAILY BACKUP JOB
Last ping 6 minutes ago, next expected in 24 minutes
Up

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

New
Created, no pings received yet.
Up
Latest ping arrived within interval + grace_period.
Down
Grace period exceeded, alert opened and sent.

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.


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

bash
/path/to/job.sh && curl -sS -X POST "$PING_URL"

Separate success from failure

bash
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

python
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?