Cron & heartbeat monitoring

Get told when a scheduled job doesn't run.

Your job sends one HTTP request when it finishes. If the request doesn't arrive on schedule, FlatLyne alerts you by email, Slack, PagerDuty or webhook.

Start freeRead the docs10 checks free. Sign in with Google.
crontab -e
# before
0 2 * * * /usr/local/bin/backup.sh

# after: one ping, only if the backup succeeded
0 2 * * * /usr/local/bin/backup.sh && curl -fsS -m 10 --retry 5 https://api.flatlyne.com/9f3c2a71e4b84d0c

GET or POST/start /fail /{exit_code}body up to 10 KB storedcron + time zone, or interval

01 / Send a ping

Works with anything that can make an HTTP request.

Every check gets its own URL. Add /start to measure how long a run takes, /fail to report a failure, or an exit code to send your job's own result.

# ping only if the job succeeded0 2 * * * /usr/local/bin/backup.sh && curl -fsS -m 10 --retry 5 https://api.flatlyne.com/9f3c2a71e4b84d0c # or report the exit code either way0 2 * * * /usr/local/bin/backup.sh; curl -fsS -m 10 https://api.flatlyne.com/9f3c2a71e4b84d0c/$?

what your job sends, and what comes back

$ curl -v https://api.flatlyne.com/9f3c2a71e4b84d0c/start
> GET /9f3c2a71e4b84d0c/start HTTP/1.1
> Host: api.flatlyne.com
> User-Agent: curl/8.7.1
< HTTP/1.1 200 OK
< Content-Type: text/plain
PONG

$ pg_dump app | gzip > /backups/app.sql.gz
$ curl -fsS --data-binary @/var/log/backup.log \
    https://api.flatlyne.com/9f3c2a71e4b84d0c/$?
< HTTP/1.1 200 OK
PONG

# status: up · duration 3m 42s · exit 0
# body: first 10 KB of backup.log, kept with the ping
/{token}

The run finished successfully.

Up
/{token}/start

The run started. The next success is timed from here.

no change
/{token}/fail

The run failed. You get an alert right away, without waiting for the grace period.

Down
/{token}/{exit_code}

0 counts as success. Any other number counts as a failure.

UpDown
/{ping_key}/{slug}

One key per project. Ping any check by its slug, so you can template it in Helm or Terraform.

same as above

02 / When it doesn't run

What happens at 02:00 when the backup doesn't start.

This is the record for nightly-backup on the night its host was rebooted for patching. Cron never fired, so no ping arrived. The grace period ran out, one alert went to each channel, and everything resolved when the on-call engineer re-ran the job.

Upnightly-backup0 2 * * * · UTC · grace 30m
Event log for nightly-backup
02:00:00GraceExpected ping missing. Grace period of 30 minutes starts. No alert yet.
02:30:00DownGrace period over with no ping. The check is down.
02:30:01emailSent to [email protected]: “[FlatLyne] nightly-backup is DOWN”
02:30:02slackPosted to #ops
02:30:02pagerdutyIncident #1042 triggered, routed to on-call: primary
02:30:02webhookPOST hooks.acme.dev/flatlyne, response 204, signed with X-FlatLyne-Signature
02:38:10/startRun started from 10.0.4.17. The on-call engineer re-ran the job.
02:41:52UpSuccess ping, exit 0, run took 3m 42s, 1.2 KB log attached. PagerDuty #1042 resolved. “is UP” sent to email and Slack.

Email02:30:01

[FlatLyne] nightly-backup is DOWN

Schedule
0 2 * * * UTC
Last ping
Fri 02:00:41
Down since
Sat 02:30:00

Slack · #ops02:30:02

nightly-backup is DOWN

Total pings
412
Last ping
success
Changed at
Sat 02:30

PagerDuty02:30:02

#1042 nightly-backup is down

Service
FlatLyne
Urgency
high
Resolves
on next ping

Webhook bodyyou write it

{
  "text": "$NAME is $STATUS",
  "was": "$OLD_STATUS",
  "exit": "$EXITSTATUS",
  "url": "$CHECK_URL",
  "at": "$NOW"
}

03 / What people monitor

The jobs that fail without anyone noticing.

Each of these fails silently in its own way. Here is where to put the ping for each one.

Database backups

pg_dump … && curl $URL

Disk full, credentials rotated, or the cron host replaced and nobody copied the crontab.

Kubernetes CronJobs

Last step of the container command

The CronJob stops being scheduled (startingDeadlineSeconds, suspended, cluster upgrade), so no pod ever fails.

GitHub Actions schedules

Final run: curl step

Scheduled workflows are disabled after 60 days without repository activity.

systemd timers

ExecStartPost= in the service unit

The timer runs on a host that was decommissioned, or Persistent= was never set.

Queue workers

Interval check, ping every loop

Celery or Sidekiq is alive but stuck: the process is up and the queue isn't moving.

Certificate renewals

certbot renew --deploy-hook

Renewal broke 60 days ago. You find out from a browser warning.

04 / Credentials

A leaked ping URL can ping one check. Nothing more.

Each credential can do one thing, and every one can be revoked. Ping URLs are encrypted at rest. Keys are stored only as SHA-256 hashes.

On Pro, rotate without breaking a job: create a new key, deploy it, then revoke the old one.

How we handle credentials
Ping URLPing one checkstored encryptedrotate regenerate
Project ping keyPing any check in one project, by slugstored sha-256rotate many live, revoke
API keyManage one project. Never billing or ownership.stored sha-256rotate many live, revoke
SessionWhat you can do when signed in with Googlestored httponly cookierotate sign out

05 / Pricing

Free for 10 checks. Pro from $9 a month.

Every plan alerts by email, Slack, PagerDuty and webhook.

Billing period
Free$0Free foreverStart free
Checks
10
Projects
1
Seats
1
Alert channels
2
Ping history per check
100
Shortest schedule
1 min
Revoke and regenerate ping URLs
—
WhatsApp / phone-call alerts
—
Support
docs
Pro$12/monthBilled monthlyUpgrade to Pro
Checks
100
Projects
10
Seats
10
Alert channels
unlimited
Ping history per check
1,000
Shortest schedule
30 s
Revoke and regenerate ping URLs
yes
WhatsApp / phone-call alerts
50 / 20 a month
Support
email
BusinessCustomPriced for your teamContact us
Checks
100+
Projects
10+
Seats
10+
Alert channels
unlimited
Ping history per check
1,000
Shortest schedule
30 s
Revoke and regenerate ping URLs
yes
WhatsApp / phone-call alerts
higher
Support
priority email

Early prices stay yours for as long as you're subscribed. New customers will later pay $15/month, or $12/month billed yearly. Full plan details