GUIDE · FLY.IO · SCHEDULED MACHINES · FREE

Monitor Fly.io scheduled Machines — detect failed and missed cron runs

Fly.io Machines can run on a cron schedule using the --schedule flag 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.


Setup: two approaches — both with one ping

Use --schedule for simple single jobs; use supercronic for multiple schedules in one container.

Create a heartbeat monitor in LastPing

In the console, create a monitor with the same schedule as your Fly Machine (standard unix 5-field cron, UTC). 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 fly machine run my-registry/my-job:latest \ --schedule "0 3 * * *" \ # 03:00 UTC 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/fail fires; incident opens immediately.
  • Machine not started — scheduled window passes, no ping → incident opens on silence.
  • Hung Machine/start arrived, 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?

    Two main approaches: (1) fly machine run --schedule "0 3 * * *" creates a Machine that starts on a cron schedule, runs its process once, and stops. Good for simple single-purpose jobs. (2) supercronic inside a long-running Machine — run supercronic as the container entrypoint with a crontab file. Good for multiple schedules, complex jobs, or teams already familiar with crontab syntax.

  • Does Fly.io alert when a scheduled Machine fails?

    No. You can view exit codes and logs via fly logs and fly 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, Telegram, or Discord.

  • What timezone does Fly.io use for scheduled Machines?

    Fly.io scheduled Machines use UTC for the --schedule expression. Write all times in UTC. If you're using supercronic with a crontab, add TZ=UTC or set the timezone via your Dockerfile to avoid surprises.

  • Is this free?

    Yes. LastPing is free and fully hosted with no monitor cap and no paid tier. See vs Healthchecks.io and vs Cronitor.

FREE · FULLY HOSTED · NO PAID TIER

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.