Skip to content

Cron / heartbeat checks

A cron check (also called a heartbeat or deadman’s switch) is the inverse of an HTTP check. Instead of SiteQwality calling your service, your service calls SiteQwality at the end of each successful run. SiteQwality alerts when the expected ping doesn’t arrive on time.

The pattern is simple:

# At the end of your nightly backup script
curl -X POST https://ping.siteqwality.com/<account-id>/<cron-job-id>

If the expected ping stops arriving, the check flips to failure and notifications fire.

  • Backups, ETL jobs, batch jobs. You want to know when they don’t complete, not just when the host is up.
  • Cleanup tasks (purge old data, rotate logs, compact tables) where silence is the failure mode.
  • External cron services (cron-job.org, EventBridge, GitHub Actions schedules) that don’t have built-in failure alerting.
  • Don’t use cron checks for “is my service running?” That’s an HTTP check job.
  • Don’t use them for “is the queue draining?” That’s a metric: emit one and alert on it via a metrics-backed dashboard.
  1. You create a cron check in SiteQwality with a check_interval_seconds, say 86400 for a daily job. SiteQwality returns a cron_job_id.
  2. Your job pings https://ping.siteqwality.com/<account-id>/<cron-job-id> at the end of every successful run.
  3. SiteQwality records each ping with a timestamp, source IP, and headers.
  4. Each cron check gets its own evaluation schedule (an AWS Scheduler entry) that fires at the same cadence as check_interval_seconds. At each evaluation, the check fails when the newest ping is older than check_interval_seconds (or when no ping has ever arrived).
  5. The next successful ping flips status back to healthy at the following evaluation.

Because the evaluation runs at the same cadence as the expected pings, a missed ping is detected between one and two intervals after the last successful one, depending on how the two schedules line up. A slightly-delayed job (running 24h 5m instead of exactly 24h) usually doesn’t page for the same reason; see grace period notes.

FieldDefaultDescription
friendly_nameoptionalDisplay name.
check_interval_secondsrequiredExpected interval between pings, in seconds. Validated against AWS Scheduler rate expressions.
group_notification_ids[]Notification groups to fire on state change. Cap of 10.
stateactiveactive or paused. Paused checks don’t alert.
tags[]For grouping and matching against maintenance windows.

Every ping captures:

  • A unique id for the receipt.
  • created_at: server-side timestamp.
  • receiving_address: IP from X-Forwarded-For.
  • receiving_headers: entire headers map (useful for debugging which job pinged).

These are queryable via GET /cron/job/{cron_job_id}/recent.

Cron checks are included on every plan. There’s a soft monthly cap on total pings per account on the free tier; see your Settings → Billing → Usage page.