Your nightly backup stopped running 9 days ago. Nobody noticed.
Agent Pulse is heartbeat monitoring that alerts you when a cron job, background worker, backup or AI agent stops checking in.
Give every cron job, background worker, backup and AI agent its own ping URL. When a ping doesn't arrive on schedule, Sentinely emails you and calls your webhook.
0 3 * * * /usr/local/bin/backup.sh && curl -fsS https://sentinely.app/api/beat/<token>From $19/month with 25 heartbeat monitors. Every plan starts with a 14-day trial.
How do I set up heartbeat monitoring?
Uptime checks ask a server whether it is up. A heartbeat monitor waits for your job to report in, and alerts you on silence.
Create a monitor
Name the job, pick how often it should run (every minute up to once a day) and add a grace period. Sentinely gives the job its own ping URL.
Ping it when the job succeeds
Add one HTTP request as the last step of the job. Add ?status=fail, or send {"status":"fail"}, when the job runs but fails.
Hear about it when it goes quiet
No ping by the deadline (interval plus grace) opens an incident and alerts your email list and webhook. When pings resume, you get a recovery notice.
One list of everything that runs on a schedule
Each monitor shows its schedule, its grace window and when it last checked in. Missed and failed jobs rise to the top, and each one has an incident with its start and recovery time.
- Intervals from every minute to once a day
- Pause a monitor during planned maintenance
- Rotate a token without losing the monitor history
- Missednightly-db-backupDaily, 30 min grace · last beat 9 days ago
- Missedresearch-agentEvery 15 min, 5 min grace · last beat 47 min ago
- Failedinvoice-exportEvery hour, 10 min grace · last beat 12 min ago
- Healthyqueue-workerEvery minute, 2 min grace · last beat 28 sec ago
- Healthysitemap-rebuildEvery 6 hours, 15 min grace · last beat 2 hours ago
What does Agent Pulse include?
A unique ping URL per job
Every monitor has its own secret token, so one noisy job never hides another. GET, HEAD and POST all count as a heartbeat.
Grace windows
Jobs drift. Allow a few extra minutes before Sentinely calls a run missed, so slow nights do not page you.
Missed, failed and recovered alerts
Alerts go to the email addresses on the monitor and to an optional Slack-compatible HTTPS webhook. Recovery notices follow automatically.
Explicit failure reports
A job that runs but fails can say so. A failed heartbeat opens an incident immediately instead of waiting for the window to lapse.
Rotatable tokens
If a ping URL ends up in a log or a public repo, rotate the token. The old URL stops working and the monitor keeps its history.
Run context for agents
Attach a task name, token count, cost in USD and a small metadata object to each heartbeat, so every run is recorded with what it did.
Works with anything that can make an HTTP request
Replace <token> with the token from your monitor. Each snippet is complete; copy it into your job.
Cron
Chain the ping after the job with &&, so it only fires when the job exits successfully.
# Every 15 minutes: ping only if sync.sh succeeds
*/15 * * * * /opt/jobs/sync.sh && curl -fsS -m 10 --retry 3 https://sentinely.app/api/beat/<token> > /dev/nullGitHub Actions
Report success and failure from a scheduled workflow. Keep the token in a repository secret.
- name: Heartbeat
if: success()
run: curl -fsS -m 10 --retry 3 "https://sentinely.app/api/beat/${{ secrets.SENTINELY_BEAT_TOKEN }}"
- name: Report failure
if: failure()
run: curl -fsS -m 10 "https://sentinely.app/api/beat/${{ secrets.SENTINELY_BEAT_TOKEN }}?status=fail"Python
Wrap the job, report the outcome, and re-raise so your scheduler still sees the error.
import requests
BEAT_URL = "https://sentinely.app/api/beat/<token>"
try:
run_nightly_export()
requests.post(BEAT_URL, json={"status": "ok", "task": "nightly-export"}, timeout=10)
except Exception:
requests.post(BEAT_URL, json={"status": "fail", "task": "nightly-export"}, timeout=10)
raiseNode.js
Call it at the end of each worker cycle. A failed heartbeat should never crash the worker.
const BEAT_URL = 'https://sentinely.app/api/beat/<token>';
export async function beat(status = 'ok') {
await fetch(BEAT_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ status, task: 'queue-worker' }),
signal: AbortSignal.timeout(10_000),
}).catch(() => {});
}
await processBatch();
await beat();LangGraph or any agent loop
Beat once per completed task, not per step. An agent that hangs or loops never completes, so the heartbeat stops.
import requests
BEAT_URL = "https://sentinely.app/api/beat/<token>"
graph = build_research_graph() # your compiled LangGraph graph
while True:
task = next_task()
result = graph.invoke({"task": task})
payload = {"status": "ok", "task": task.name}
usage = result.get("usage", {})
if "total_tokens" in usage:
payload["tokens"] = usage["total_tokens"]
requests.post(BEAT_URL, json=payload, timeout=10)Why do AI agents need heartbeat monitoring?
Tracing tools alert on the telemetry an agent sends. An agent that has hung or crashed sends nothing, so nothing fires. Agent Pulse turns that around: it alerts on the absence of a heartbeat.
Send one heartbeat per completed task. If the agent stops finishing tasks, for any reason, the heartbeats stop and you hear about it. Include token counts and cost with each heartbeat to keep a record of what every run did.
Failures a heartbeat catches
- A tool call that never returns, leaving the process alive but doing nothing
- A loop that retries the same step until the token budget runs out
- A crash on deploy or an out-of-memory kill with no one watching the logs
- A rate-limit backoff that quietly stretches into hours
How much does Agent Pulse cost?
Agent Pulse is included with uptime checks, server monitoring and status pages. No per-check or per-alert charges.
25 heartbeat monitors
100 heartbeat monitors
500 heartbeat monitors
Agent Pulse questions
What counts as a missed heartbeat?
Each monitor has an expected interval and a grace period. If no heartbeat arrives within the interval plus the grace period after the last one, Sentinely marks the monitor down, opens an incident and sends alerts.
How quickly are missed runs detected?
Sentinely checks every monitor once a minute, so you are alerted within about a minute of the grace period running out.
Can a job report that it failed?
Yes. Request the ping URL with ?status=fail, or POST {"status":"fail"}. A failed heartbeat opens an incident straight away. The next successful heartbeat resolves it.
Where do alerts go?
To the email addresses you list on the monitor, and to an optional Slack-compatible HTTPS webhook. You get a recovery notice when heartbeats resume.
What if my ping URL leaks?
Rotate the token from the monitor menu. The old URL stops working immediately; update your job with the new one.
Which languages are supported?
Anything that can make an HTTP request: shell scripts, cron, CI pipelines, Python, Node.js, Go, Ruby, serverless functions and agent frameworks.
How is this different from Ping?
Ping checks a URL from the outside. Agent Pulse waits for your job to check in, which covers work that has no URL: backups, queue workers, scheduled scripts and AI agents.
Is there a free plan?
No. Every plan starts with a 14-day trial. Indie is $19/month with 25 heartbeat monitors; Agency and Scale include 100 and 500.
Works with the rest of Sentinely
- PingWebsite, API, TCP and DNS uptime checks every minute.
- PulseLinux server metrics, services, ports and stale-agent alerts.
- StatusA public status page for the monitors you choose.
- GuardAWS spend spikes and resource changes, read-only.
Every product is included in one plan. Compare Indie, Agency and Scale
Find out from an alert, not from a customer.
Create a monitor, add one line to your job, and stop the job on purpose to see the alert arrive. It takes about five minutes.
Start 14-day trial