Cron job notifications
Cron jobs run in the dark. You assume they worked. You find out otherwise when a user reports stale data, a backup is missing, or a report never arrived.
Here’s how to know immediately — when it runs, when it finishes, and when it doesn’t.
The basic pattern
Add to the beginning and end of any script:
#!/bin/bash
set -euo pipefail
TRIGGER_FYI_SECRET_KEY="your_key_here"
fyi() {
curl -s -X POST "https://trigger.fyi/$TRIGGER_FYI_SECRET_KEY" \
-H "Content-Type: text/plain" \
-d "$1" &>/dev/null
}
START=$(date +%s)
# Your cron work
rsync -az /data/ /backup/
ELAPSED=$(($(date +%s) - START))
fyi "Backup complete: ${ELAPSED}s"Add a trap for failures:
#!/bin/bash
set -euo pipefail
notify_fail() {
local line=$1
curl -s -X POST "https://trigger.fyi/$TRIGGER_FYI_SECRET_KEY" \
-H "Content-Type: application/json" \
-d "{\"title\":\"Backup failed\",\"body\":\"Line $line\",\"level\":\"critical\"}" &>/dev/null
}
trap 'notify_fail $LINENO' ERR
# Your work hereVercel Cron Jobs
// app/api/cron/sync/route.ts
import { NextResponse } from "next/server"
import fyi from "trigger.fyi"
export const runtime = "nodejs"
export async function GET(req: Request) {
// Verify Vercel cron secret
if (req.headers.get("authorization") !== `Bearer ${process.env.CRON_SECRET}`) {
return new Response("Unauthorized", { status: 401 })
}
const start = Date.now()
try {
const result = await runSync()
const elapsed = Math.round((Date.now() - start) / 1000)
await fyi("Sync complete", {
body: `${result.count} records · ${elapsed}s`,
cron: "sync"
})
return NextResponse.json({ ok: true, count: result.count })
} catch (err) {
await fyi.critical("Sync failed", {
body: err instanceof Error ? err.message : String(err),
cron: "sync"
})
return NextResponse.json({ ok: false }, { status: 500 })
}
}In vercel.json:
{
"crons": [
{
"path": "/api/cron/sync",
"schedule": "0 2 * * *"
}
]
}GitHub Actions scheduled jobs
name: Nightly Sync
on:
schedule:
- cron: "0 2 * * *"
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run sync
- name: Notify
if: always()
run: |
STATUS="${{ job.status }}"
if [ "$STATUS" = "success" ]; then
LEVEL="log"
TITLE="Nightly sync complete"
else
LEVEL="critical"
TITLE="Nightly sync failed"
fi
curl -s -X POST "https://trigger.fyi/$TRIGGER_FYI_SECRET_KEY" \
-H "Content-Type: application/json" \
-d "{\"title\":\"$TITLE\",\"level\":\"$LEVEL\"}"
env:
TRIGGER_FYI_SECRET_KEY: ${{ secrets.TRIGGER_FYI_SECRET_KEY }}Successful runs use log — in the feed, no push. Failures use critical — push immediately.
Python cron scripts
#!/usr/bin/env python3
import time
from trigger_fyi import fyi
start = time.time()
try:
result = run_nightly_report()
elapsed = int(time.time() - start)
fyi("Report generated",
body=f"{result['rows']} rows · {elapsed}s",
cron="nightly_report"
)
except Exception as e:
fyi.critical("Report failed", body=str(e), cron="nightly_report")
raiseIn crontab:
0 2 * * * TRIGGER_FYI_SECRET_KEY=your_key /usr/local/bin/python3 /scripts/nightly_report.pyWhat to use for normal runs
For cron jobs that run multiple times per day, use fyi.log() for successes — it records in the feed without pushing. You can see the history later if needed. Reserve fyi() (push) for the end of a longer daily/weekly job. Reserve fyi.critical() for failures.
# Hourly sync — log only
fyi.log("Hourly sync complete", body=f"{count} items")
# Daily backup — push when done
fyi("Daily backup complete", body=f"{size}GB in {elapsed}s")
# Failure — always push
fyi.critical("Backup failed", body=error_message)Missed runs
If your cron job didn’t run at all, you won’t get a notification — silence is ambiguous.
For critical jobs, consider a “heartbeat” approach: push a log notification on each run, and if you don’t see one in the feed within the expected window, you know it didn’t fire.
For more robust missed-run detection, a dedicated monitoring tool (Cronitor, Healthchecks.io) is better suited. trigger.fyi is about knowing what happened; detecting what didn’t happen is a different problem.
Related: Push notifications for cron jobs · Background job notifications · Push notifications from bash · What is trigger.fyi?