Skip to content

Scheduled Jobs

Cron jobs and scheduled tasks are a perfect fit for Island Pulse. They run unattended, often at odd hours, and you only care about two things: did it start on time, and did it finish successfully?

The three-push pattern

Model every scheduled job with three posts: start, optional mid-run progress, and done.

#!/bin/bash
PULSE_URL="YOUR_WEBHOOK_URL"
JOB="nightly-report"
# 1. Start
curl -s -X POST "$PULSE_URL" \
-H "Content-Type: application/json" \
-d "{
\"job_id\": \"$JOB\",
\"layout\": \"progress\",
\"message\": \"Report generation started\",
\"metric\": \"Step 1/3\",
\"progress\": 0.05,
\"status\": \"running\"
}"
# 2. Your actual job
./generate_report.sh || {
curl -s -X POST "$PULSE_URL" \
-H "Content-Type: application/json" \
-d "{\"job_id\":\"$JOB\",\"layout\":\"progress\",\"message\":\"Report failed during generation\",\"progress\":0,\"status\":\"failed\"}"
exit 1
}
# 3. Done
curl -s -X POST "$PULSE_URL" \
-H "Content-Type: application/json" \
-d "{
\"job_id\": \"$JOB\",
\"layout\": \"progress\",
\"message\": \"Report ready. Sent to 12 recipients.\",
\"metric\": \"Done\",
\"progress\": 1.0,
\"status\": \"success\"
}"

Wrap this with your cron scheduler (crontab, systemd.timer, etc.) and you’ll see every run’s status on your Lock Screen without checking a log.

Python wrapper

For Python-based jobs, use a context manager to automatically send start/done/fail notifications:

import requests, contextlib, traceback
PULSE_URL = "YOUR_WEBHOOK_URL"
@contextlib.contextmanager
def pulse_job(job_id: str, start_message: str = "Job started"):
"""Context manager that sends start, success, and failure notifications."""
def notify(msg, status, progress=None):
payload = {
"job_id": job_id,
"layout": "progress",
"message": msg,
"status": status,
}
if progress is not None:
payload["progress"] = progress
requests.post(PULSE_URL, json=payload, timeout=5)
notify(start_message, "running", 0.05)
try:
yield notify # caller can call notify() mid-job for progress updates
notify("Completed successfully", "success", 1.0)
except Exception as e:
notify(f"Failed: {str(e)[:60]}", "failed", 0)
raise
# Usage
with pulse_job("invoice-sync", "Syncing invoices from Stripe") as update:
invoices = fetch_invoices() # step 1
update("Processing invoices…", "running", 0.4)
process(invoices) # step 2
update("Uploading to accounting…", "running", 0.8)
upload(invoices) # step 3

Node.js / TypeScript

const PULSE_URL = process.env.ISLAND_PULSE_URL!;
async function notify(jobId: string, message: string, status: "running" | "success" | "failed", progress?: number) {
await fetch(PULSE_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ job_id: jobId, layout: "progress", message, status, progress }),
});
}
async function runNightlySync() {
const job = "nightly-sync";
await notify(job, "Sync started", "running", 0.0);
try {
await fetchData();
await notify(job, "Data fetched, transforming…", "running", 0.5);
await transformAndLoad();
await notify(job, `Sync complete. ${Date.now() - start}ms`, "success", 1.0);
} catch (err) {
await notify(job, `Sync failed: ${err.message}`, "failed");
throw err;
}
}

Heartbeat / dead man’s switch

Post a success update from each cron run to confirm it ran on schedule. If a run is missed (job died, server down), the activity goes stale, you’ll notice it hasn’t updated.

Terminal window
# Add to the end of any cron job as a health check
curl -s -X POST "YOUR_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d "{
\"job_id\": \"heartbeat\",
\"layout\": \"score\",
\"metric\": \"$(date +%H:%M)\",
\"message\": \"Last successful run\",
\"status\": \"running\"
}"

The metric shows the time of the last successful run. If it stops updating, you know the job missed a cycle.

Use names that make it obvious what failed when you’re half-awake at 2am:

daily-report
invoice-sync
db-backup-prod
cache-warm
email-digest

Avoid generic names like cron-1 or job, they mean nothing in your Lock Screen history.