getting started
Quickstart
Monitor your first cron job in five minutes. You’ll create a monitor, add one line to your job, and watch the first ping arrive.
-
Create a monitor
Section titled “Create a monitor”From the dashboard, click New monitor. Set the period to how often your job runs and add a grace window for normal jitter — a job scheduled every hour that usually takes two minutes wants a period of
1hand a grace of a few minutes, not zero.Each monitor gets its own ping URL. The token in it is the monitor’s identity, so treat it like a credential:
# your monitor's unique ping URLhttps://ping.deadpost.dev/00000000-0000-7000-8000-000000000001 -
Add the ping
Section titled “Add the ping”Append a request to the end of your job. If the job succeeds, the ping is sent; if it fails, the shell short-circuits and no ping goes out — which is exactly the signal deadpost is watching for.
0 9 * * * pg_dump prod | gzip > backup.sql.gz && curl -fsS https://ping.deadpost.dev/00000000-0000-7000-8000-000000000001 -
Watch it arrive
Section titled “Watch it arrive”The monitor flips from
pendingtohealthythe moment the first ping lands. From then on the clock is running: if a ping doesn’t arrive within the period plus its grace window, the monitor goes late, and then down.
You are not alerted when something breaks loudly. You are alerted when something stops happening quietly.
Beyond a heartbeat
Section titled “Beyond a heartbeat”curl can say “I finished”. It can’t say how long the job took, that it failed
and why, or how many rows it processed — and it can’t buffer a ping through a
network blip. That is what the SDKs add:
import deadpost
# The simple case: "my job ran and succeeded".rotate_logs()deadpost.ping()
# Bracket the work instead, and you also get its duration — plus the# difference between "not started yet" and "started an hour ago and# never came back".with deadpost.run() as run: rows, size = dump_database() # Tag the numbers that describe the work, not just that it happened: # a backup that exits 0 having written 2 MB is green everywhere else. run.tag(rows=rows, bytes=size)
# An exception reports /fail — forcing the monitor down immediately# rather than waiting out its grace period — and is re-raised unchanged.with deadpost.run("nightly-etl", env="prod") as run: run.tag(rows=export_to_warehouse())import { ping, run } from '@deadpost/sdk';
// The simple case: "my job ran and succeeded".await rotateLogs();await ping();
// Bracket the work instead, and you also get its duration — plus the// difference between "not started yet" and "started an hour ago and// never came back".await run(async (job) => { const { rows, bytes } = await dumpDatabase(); // Tag the numbers that describe the work, not just that it happened: // a backup that exits 0 having written 2 MB is green everywhere else. job.tag({ rows, bytes });});
// A throw reports /fail — forcing the monitor down immediately rather// than waiting out its grace period — and is re-thrown unchanged.await run('nightly-etl', { env: 'prod' }, async (job) => { job.tag({ rows: await exportToWarehouse() });});# Wrap the crontab line you already have. Exit code, stdout and stderr# all pass straight through — `&&`, `set -e` and cron's mail keep working.deadpost run -- ./backup.sh
# Tag the numbers that describe the work, not just that it happened:# a backup that exits 0 having written 2 MB is green everywhere else.deadpost run --tag rows=1240918 --tag bytes=14002003912 -- ./dump.sh
# Kill a job that hangs, and hear about it as a failure rather than# as silence. --capture attaches the failing job's output to the alert.deadpost run --timeout 30m --capture -- ./import.sh
# Several jobs on one box? Name them; -m picks the monitor.deadpost run -m nightly-etl -- ./etl.sh
# Already a pipeline? Just the heartbeat../rotate-logs.sh && deadpost ping