Fly.io has no native cron. You choose how to schedule jobs — Supercronic in a process, Cron Manager,
or Fly Machines on a timer. None of these options alert you when a job fails or silently does nothing.
DeadManCheck does.
How cron works on Fly.io
Fly.io offers three main approaches for scheduled jobs, each with different tradeoffs:
-
Supercronic (most common) — a container-native
cron replacement. You add a crontab file, install Supercronic in your Dockerfile, and run it
as a separate
cron process group in
fly.toml. Simple setup, but no
built-in alerting when jobs fail.
-
Cron Manager — Fly's batteries-included solution
for isolated, auditable job runs. Spins up a temporary Machine per job. Provides isolation and
audit logs, but still no external alerting if a job exits non-zero or does nothing.
-
Fly Machine timers — schedule a Machine to start
hourly, daily, or weekly. Coarse-grained control; no failure notifications.
In all three cases, the gap is the same: Fly.io logs the run, but doesn't page you when
something goes wrong.
Adding DeadManCheck to a Supercronic setup
If you're using Supercronic, wrap your cron commands to send start/success/fail pings.
Your crontab entry becomes a call to a wrapper script:
crontab (at your project root)
0 2 * * * /app/scripts/run-monitored.sh /app/run-export.sh
/app/scripts/run-monitored.sh
#!/bin/bash
set -euo pipefail
TOKEN="${DEADMANCHECK_TOKEN}"
BASE="https://deadmancheck.io/ping/${TOKEN}"
curl -fsS "${BASE}/start" > /dev/null
trap 'curl -fsS "${BASE}/fail" > /dev/null' ERR
# Run the actual job, capture output count if applicable
"$@"
curl -fsS "${BASE}" > /dev/null
Python job with output assertion
import requests, os, sys
TOKEN = os.environ["DEADMANCHECK_TOKEN"]
BASE = f"https://deadmancheck.io/ping/{TOKEN}"
def main():
requests.get(f"{BASE}/start", timeout=5)
try:
records = run_job()
# count=records triggers output assertion alert if 0
requests.get(BASE, params={"count": records}, timeout=5)
except Exception:
requests.get(f"{BASE}/fail", timeout=5)
sys.exit(1)
if __name__ == "__main__":
main()
Setting the secret on Fly.io
fly secrets set DEADMANCHECK_TOKEN=your-monitor-token
Fly secrets are automatically injected as environment variables into all Machines in the app,
including your cron process group.
Output assertions for Fly.io jobs
Whether you use Supercronic, Cron Manager, or a Machine timer, Fly.io has no concept of
"this job ran but processed nothing." A script that connects to a database, finds no rows,
and exits 0 looks identical to a successful run.
DeadManCheck's output assertions let you configure a
minimum count threshold. Pass ?count=
with your ping, set the threshold to count > 0,
and you'll get alerted when the job runs but does nothing useful. Learn more about
output assertions →
Start monitoring free — no credit card needed
Free for 5 monitors. $12/mo for 100. Self-host for free.