Scheduling health checks with cron

Cron's one-minute floor is too coarse for most health checks — here's what to use instead, and when cron is fine.

The problem

Cron's finest granularity is once per minute. For an externally-facing service, a one-minute-or-slower check means up to a minute of undetected downtime before anything even starts noticing, and cron itself has no retry, backoff, or alerting — it just runs a script; turning a failed check into a page is entirely on you to build.

Purpose-built monitoring (uptime checkers, Healthchecks-style dead-man's-switches, or norc's own run-history view for scheduled jobs) already does sub-minute polling, retries, and alert routing. Reaching for cron here usually means rebuilding a worse version of a tool that already exists.

Use a real monitoring tool for anything user-facing; reserve cron for internal, low-urgency checks.

If a check needs to fire faster than once a minute, or needs retries/backoff/on-call paging when it fails, that's a monitoring product's job, not cron's. A cron-based check script is fine for low-urgency internal signals — "did this batch job leave a lock file behind," "is this internal service still listening" — where a delay of a few minutes before anyone notices is acceptable.

Recommended schedule

*/5 * * * *

Every 5 minutes is a reasonable floor for a low-urgency internal check. Anything more time-sensitive than that belongs in dedicated monitoring rather than cron.

Example crontab entry

# norc: healthcheck-internal Check internal queue worker is listening
*/5 * * * * /usr/bin/curl -sf --max-time 5 http://127.0.0.1:9200/healthz || /opt/scripts/alert.sh "worker down"

Failure modes to watch for

  • No --max-time on the check request: a hung endpoint makes the check itself hang, delaying the next scheduled run instead of failing fast.
  • Alerting only on a single failed check with no debounce, paging on a single dropped packet instead of a real outage.
  • The alert script itself has a single point of failure (one SMTP relay, one webhook) with no fallback, so the exact outage that should trigger an alert also takes down the alerting path.
  • Checking the process is running (`pgrep`) instead of that it's actually serving traffic — a hung-but-alive process passes a liveness check while failing every real request.

How norc helps

For scheduled jobs specifically (not general uptime monitoring), norc already tracks whether each run happened and what it returned — often enough signal on its own without a separate check script.