Cron jobs fail silently. That is their defining characteristic. A backup script starts throwing errors at 3 AM. A data pipeline job gets killed by an OOM condition. A scheduled report just stops running because someone renamed a config file. In every case, nothing alerts you. The job does not phone home on failure — it simply does not run, and the absence of activity is invisible until someone notices the data is stale, the backup is missing, or the report never showed up.
Traditional uptime monitoring does not help here. Tools like CronAlert's HTTP monitors work by pinging your URL on a schedule and alerting when the response is unhealthy. But cron jobs, background workers, and scheduled tasks do not expose a URL to check. They run, do their work, and exit. There is nothing to ping from the outside.
Heartbeat monitoring flips the model. Instead of CronAlert checking on your service, your service checks in with CronAlert. If CronAlert does not hear from your job within the expected window, it assumes something went wrong and fires an alert.
How heartbeat monitoring works
The concept is simple. When you create a heartbeat monitor in CronAlert, you get a unique ping URL:
https://cronalert.com/api/heartbeat/your-unique-token The token is a 32-character unique identifier assigned to your monitor. You add a request to this URL at the end of your cron job or background task. Every time the job completes successfully, it pings the URL. CronAlert records the timestamp and marks the monitor as UP.
If no ping arrives within the expected check interval, CronAlert transitions the monitor to DOWN with the error message: Heartbeat not received within expected [interval]s interval. At that point, your configured alert channels fire — email, Slack, Discord, webhook, whatever you have set up.
The monitor tracks three key fields: lastPingedAt (when the last successful ping was received), lastStatus (up, down, or unknown for newly created monitors), and the check interval that defines the expected ping frequency. The ping endpoint accepts both GET and POST requests, so you can use whichever is more convenient for your environment.
Setting it up in CronAlert
Creating a heartbeat monitor takes about 30 seconds:
- Open the CronAlert dashboard and click New Monitor
- Select Heartbeat as the monitor type
- Give it a descriptive name — something like "Nightly DB backup" or "Invoice generation job"
- Set the check interval to match your job's schedule (with some buffer)
- Choose your alert channels
Once created, the monitor detail page shows your unique ping URL. Copy it and add it to your job.
Heartbeat monitors require a Pro plan or higher. They are not available on the free tier. If you are on the free plan, you will see the heartbeat option in the UI but will need to upgrade to activate it.
Integration examples
The ping is a single HTTP request. Here is how to add it to common tools and languages.
crontab
The most straightforward case. Append a curl to the end of your cron command so it only fires after the job completes:
# Run backup at 2 AM, ping CronAlert on success
0 2 * * * /usr/local/bin/backup.sh && curl -s https://cronalert.com/api/heartbeat/TOKEN > /dev/null
The && operator is important. It means the curl only runs if backup.sh exits with code 0. If the backup fails, no ping is sent, and CronAlert alerts you. Using ; instead would ping regardless of whether the job succeeded — defeating the purpose.
Node.js
Add the ping after your job logic completes. Use a fire-and-forget pattern so the ping does not block your process if CronAlert is slow to respond:
async function runJob() {
// Your actual job logic
await processInvoices();
// Ping CronAlert on success
fetch('https://cronalert.com/api/heartbeat/TOKEN')
.catch(() => {}); // Don't let a ping failure crash the job
}
runJob(); Python
import requests
def run_pipeline():
# Your pipeline logic
extract_data()
transform_data()
load_data()
# Ping CronAlert on success
try:
requests.get('https://cronalert.com/api/heartbeat/TOKEN', timeout=10)
except requests.RequestException:
pass # Don't fail the pipeline over a ping
run_pipeline() GitHub Actions
Add the ping as a final step in your workflow. It only runs if the previous steps succeed:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run scheduled task
run: ./scripts/generate-report.sh
- name: Ping CronAlert heartbeat
if: success()
run: curl -s https://cronalert.com/api/heartbeat/TOKEN > /dev/null
The if: success() condition ensures the ping step only runs when all previous steps passed. If your report generation fails, no ping is sent.
Docker and Kubernetes
For containerized cron jobs, add the ping to the end of your entrypoint script:
#!/bin/sh
# entrypoint.sh
set -e
# Run the actual job
python /app/sync_data.py
# If we get here, the job succeeded
curl -s https://cronalert.com/api/heartbeat/TOKEN > /dev/null
The set -e flag causes the script to exit immediately on any error, so the curl at the end only executes on success. For Kubernetes CronJobs, this pattern works the same way — the heartbeat ping is just part of your container's command.
Best practices
A few things to keep in mind to get the most out of heartbeat monitoring:
- Ping only on success, never at the start. The whole point is to detect jobs that fail or do not complete. If you ping at the beginning of the job, a job that hangs halfway through still looks healthy. Always place the ping at the very end, after all meaningful work is done.
- Set the interval slightly longer than your job frequency. If your cron runs every 15 minutes, set the heartbeat interval to 20 minutes. This gives your job time to finish without triggering a false positive. For jobs with variable execution time, use your worst-case duration plus a buffer.
- Use descriptive monitor names. "Heartbeat 1" tells you nothing at 3 AM. "Nightly Postgres backup - prod" tells you exactly what failed and where to look.
- Do not let the ping crash your job. Wrap the HTTP request in a try/catch or use a fire-and-forget pattern. If CronAlert is momentarily unreachable, your job should still complete normally. The missed ping will trigger an alert, but at least the underlying work got done.
- One heartbeat per job. If you have five different cron jobs, create five heartbeat monitors. Combining multiple jobs into a single heartbeat makes it impossible to tell which one failed.
Common use cases
Heartbeat monitoring is useful anywhere you have scheduled or recurring work that is not exposed via an HTTP endpoint:
- Database backups — nightly pg_dump or mysqldump scripts. You absolutely want to know if these stop running.
- Data pipelines — ETL jobs, data syncs between services, report generation. Stale data often goes unnoticed for days.
- Background workers — Sidekiq, Celery, or BullMQ workers that process queues on a schedule. Ping after each batch completes.
- Scheduled emails — digest emails, billing reminders, weekly summaries. If the send job fails, your users get radio silence.
- Certificate and license renewal — scripts that renew SSL certs or software licenses. A missed renewal can cause outages.
- Cleanup tasks — log rotation, temp file cleanup, expired session purging. These tend to be forgotten until disk space runs out.
Frequently asked questions
Is heartbeat monitoring available on the free plan?
No. Heartbeat monitors are available on Pro ($5/month), Team ($20/month), and Business ($50/month) plans. The free plan includes standard HTTP monitors only. You can see all plans on the pricing page.
Can I use GET or POST to ping the heartbeat URL?
Both work. The endpoint at https://cronalert.com/api/heartbeat/[token] accepts GET and POST requests. Most people use GET with curl since it is simpler, but POST is fine if your HTTP client defaults to it.
What if my job takes a variable amount of time to complete?
Set your check interval to your worst-case execution time plus a comfortable buffer. If a job usually takes 2 minutes but sometimes takes 10, and it runs every 30 minutes, set the interval to 35 or 40 minutes. The goal is to avoid false alerts while still catching genuine failures within a reasonable window.
What happens if my server cannot reach CronAlert?
If the ping does not arrive within the expected interval for any reason — including network issues on your end — the monitor transitions to DOWN and alerts fire. When the next ping comes through successfully, the incident resolves automatically. To minimize noise from transient network blips, make sure your interval has enough buffer and consider wrapping the ping in a retry loop for critical jobs.
Wrapping up
HTTP monitoring tells you when your services are down. Heartbeat monitoring tells you when your jobs stopped running. They solve different problems, and most production environments need both.
If you have cron jobs, background workers, or scheduled tasks that your business depends on, add a heartbeat ping to each one. The setup is a single HTTP request at the end of your job, and it turns invisible failures into immediate alerts.
Heartbeat monitors are available on all paid CronAlert plans starting at $5/month. If you are already on a Pro, Team, or Business plan, you can create your first heartbeat monitor right now.