Blog

6 min read

Why health endpoints aren’t enough to know your app is working

A /health endpoint returning 200 feels reassuring. Your uptime monitor is green, your status page is green, everyone relaxes. The problem: a health endpoint only proves your web server can answer a request right now. It says nothing about the nightly billing run, the queue worker, or the sync job that quietly stopped three days ago.

What a health endpoint actually tells you

A typical health check answers one narrow question: can the app respond to an HTTP request at this instant? A good one might also check that the database is reachable. That is genuinely useful for load balancers and uptime monitors — it catches crashes, bad deploys, and hard outages.

But it is scoped to the request path. It runs when someone (or something) asks, and it verifies the things that are needed to serve a request. Your scheduled and background work is not in that path.

The gap: background work isn’t in the request path

Cron jobs, queue workers, and scheduled tasks run out-of-band. Nothing about serving a web request depends on last night’s report being generated. So your app can be perfectly “healthy” — 200 on /health, database up, pages loading — while a job that matters has not run since the last deploy silently disabled it.

A concrete example

Imagine a nightly job that emails customers their usage invoices. A refactor renames the script the cron entry calls. The web app is untouched and stays green. For two weeks /health returns 200 every minute — and not a single invoice goes out. You find out when a customer asks where their bill is. The health endpoint was never going to catch this, because sending invoices was never part of answering a web request.

Heartbeats: the inverse of a health check

A health check is a pull — something reaches in and asks. A heartbeat is a push — the job itself reports out when it succeeds. You give each job a unique URL and it pings that URL on a successful run. The monitor knows the expected schedule, so a missing ping is an immediate, unambiguous signal.

the whole integration
# at the end of the job, only on success
your-nightly-job && curl -fsS https://cronmint.com/ping/YOUR-TOKEN >/dev/null

Use both — they answer different questions

This is not health-checks-versus-heartbeats. Keep your /health endpoint for uptime; it does its job well. Add heartbeats for every scheduled and background task so the work that lives outside the request path is observable too. Together they cover “is the app up?” and “did the work actually happen?”.

Never miss a silent cron failure again

Cronmint monitors your scheduled jobs and alerts you the moment one fails — or silently doesn't run. 5 jobs free, no card.

Start free

Frequently asked questions

Isn’t a health check enough for monitoring?

No. A health endpoint proves the app can serve a request right now. It cannot tell you whether a cron job or background worker ran, because that work is not part of the request path. You need heartbeat monitoring for scheduled tasks.

What is the difference between a health check and a heartbeat?

A health check is pulled — a monitor calls your endpoint to see if it responds. A heartbeat is pushed — your job calls a unique URL when it succeeds, and you are alerted if the expected ping does not arrive.

Do I need both?

Usually yes. Keep the health endpoint for uptime and add heartbeats for every scheduled or background job so out-of-band work is monitored too.