Monitor Fly.io scheduled Machines: detect failed and missed cron runs
Fly.io Machines can run on a schedule using the --schedule flag (hourly, daily, weekly or monthly) or
supercronic inside a long-running container. When a Machine exits non-zero, the run is
logged as failed, but no alert is sent. When Fly doesn't start a Machine for a scheduled
window (capacity, config change, region issue), nothing fires at all. Add one curl ping at
the end of a successful run to detect every silent failure in seconds.
Your assistant can do this for you
Monitor my Fly.io scheduled machines with LastPing
Setup: two approaches, both with one ping
Use --schedule for simple single jobs that only need an approximate hourly, daily, weekly or monthly run; use supercronic for exact times or multiple schedules in one container.
Create a heartbeat monitor in LastPing
In the console, create a monitor that matches how the Machine runs. With --schedule, use a simple interval of the same length (for example 24 hours for daily) and a grace window wide enough for Fly's approximate start time. With supercronic, use the same cron expression as your crontab. Copy the ping URL.
https://ping.lastping.dev/<your-monitor-id>
Approach A: --schedule flag on fly machine run
Wrap your command in a shell script that pings on success and sends a /fail on error. Pass it as the Machine's command.
#!/bin/sh
# entrypoint.sh — stored in your Docker image
set -e
PING_URL="https://ping.lastping.dev/${LASTPING_MONITOR_ID}"
curl -fsS -m 10 --retry 3 -o /dev/null "${PING_URL}/start" # arm overrun detection
if python /app/backup.py; then
curl -fsS -m 10 --retry 3 -o /dev/null "$PING_URL"
else
curl -fsS -m 10 --retry 3 -o /dev/null "${PING_URL}/fail"
exit 1
fi
# Deploy and schedule via flyctl.
# --schedule daily runs about once a day; Fly picks the time.
fly machine run my-registry/my-job:latest \
--schedule daily \
--env LASTPING_MONITOR_ID=<your-monitor-id> \
--region ord \
--vm-size shared-cpu-1x
Approach B: supercronic inside a long-running Machine
supercronic is a container-native cron runner with stdout/stderr logging and proper signal handling. Install it in your Dockerfile, write a crontab, and run it as the container entrypoint.
# Dockerfile — install supercronic
FROM python:3.12-slim
RUN pip install -r /app/requirements.txt
ADD https://github.com/aptible/supercronic/releases/download/v0.2.33/supercronic-linux-amd64 \
/usr/local/bin/supercronic
RUN chmod +x /usr/local/bin/supercronic
COPY crontab /etc/crontab
CMD ["supercronic", "/etc/crontab"]
# /etc/crontab — wrap each job with the ping pattern
0 3 * * * sh -c 'python /app/backup.py \
&& curl -fsS -m 10 -o /dev/null "https://ping.lastping.dev/$LASTPING_MONITOR_ID" \
|| curl -fsS -m 10 -o /dev/null "https://ping.lastping.dev/$LASTPING_MONITOR_ID/fail"'
Set the secret in your Fly app
fly secrets set LASTPING_MONITOR_ID=<your-monitor-id> --app my-job-app
Secrets are injected as environment variables at runtime and never appear in logs or image layers.
What this catches
- Non-zero exit:
/failfires; incident opens immediately. - Machine not started: scheduled window passes, no ping → incident opens on silence.
- Hung Machine:
/startarrived, success never came → overrun incident. - Recovery: next successful run closes the incident automatically.
On Render? See Render cron jobs. On Railway? See Railway. For the general pattern, see monitor cron jobs. For AI agent heartbeat monitoring via the MCP protocol, see the LastPing MCP server.
Questions people ask
-
How do I run a cron job on Fly.io?
There are two main approaches: (1) The
--scheduleflag onfly machine run(for examplefly machine run --schedule daily) starts a Machine about once per hour, day, week or month (hourly, daily, weekly or monthly; Fly picks the exact time), runs its process once, and exits. Good for simple single-purpose jobs. (2) supercronic (a cron runner designed for containers) inside a long-running Machine: run supercronic as the container entrypoint with a crontab file to manage multiple schedules inside one container. Good for exact times, multiple schedules, complex jobs, or teams already familiar with crontab syntax. Only supercronic accepts standard 5-field unix cron expressions. -
Does Fly.io alert when a scheduled Machine fails?
No. Fly.io does not send notifications when a scheduled Machine exits non-zero or when a scheduled run is missed. You can view exit codes and logs via
fly logsandfly machine status, but there is no built-in notification system for cron failures or missed runs. Dead-man's-switch monitoring fills this gap: if no ping arrives in the expected window, an incident opens and you get alerted via email, Slack, Discord, Telegram, ntfy, Pushover, Microsoft Teams, Google Chat, or a signed webhook. -
What timezone does Fly.io use for scheduled Machines?
None for
--schedule: it takes no time of day, onlyhourly,daily,weeklyormonthly, and Fly picks the approximate start time. If you're using supercronic with a crontab, addTZ=UTCor set the timezone via your Dockerfile to avoid surprises. -
Is this free?
Yes. LastPing is free for individuals with no monitor cap. See vs Healthchecks.io and vs Cronitor.
Fly.io scheduled Machines fail silently. One ping changes that.
One shell wrapper in your entrypoint. First alert in under a minute, and LastPing monitors itself the same way.