heartbeat-api

Implement a heartbeat/dead man's switch API pattern for monitoring scheduled jobs. Use when building a system where jobs must ping an API to prove they ran, and alerting fires if they don't. Triggers include "heartbeat API", "dead man's switch", "job ping", "monitoring API", "scheduled job health check", or any task implementing uptime monitoring via periodic API calls.

7 stars

Best use case

heartbeat-api is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Implement a heartbeat/dead man's switch API pattern for monitoring scheduled jobs. Use when building a system where jobs must ping an API to prove they ran, and alerting fires if they don't. Triggers include "heartbeat API", "dead man's switch", "job ping", "monitoring API", "scheduled job health check", or any task implementing uptime monitoring via periodic API calls.

Teams using heartbeat-api should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/heartbeat-api/SKILL.md --create-dirs "https://raw.githubusercontent.com/heldernoid/agentic-build-templates/main/projects/devops-infrastructure/backup-monitor/skills/heartbeat-api/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/heartbeat-api/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How heartbeat-api Compares

Feature / Agentheartbeat-apiStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Implement a heartbeat/dead man's switch API pattern for monitoring scheduled jobs. Use when building a system where jobs must ping an API to prove they ran, and alerting fires if they don't. Triggers include "heartbeat API", "dead man's switch", "job ping", "monitoring API", "scheduled job health check", or any task implementing uptime monitoring via periodic API calls.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# heartbeat-api

The heartbeat pattern for monitoring scheduled jobs: jobs ping an API to prove they ran, and alerts fire if they don't.

## Pattern Overview

```
Backup Script                  Heartbeat Server
      |                               |
      |--- POST /ping/:id/start ----->|  (job began)
      |                               |
      |    [job runs]                 |
      |                               |
      |--- POST /ping/:id/complete -->|  (job finished)
      |                               |
      |                          [alert engine checks every minute]
      |                          [if not completed in window: fire alert]
```

## When to Use

- Any scheduled script that must run on time (backups, ETL, reports, cleanups)
- Cron jobs where you need to know if they silently failed
- Long-running jobs where you need duration tracking

## Key Design Decisions

### Why heartbeat instead of log scraping

Log scraping is fragile. The heartbeat pattern is explicit: the job actively asserts it ran and succeeded. No false negatives from log format changes.

### Window calculation

```
alert_time = last_scheduled_run + expected_duration + grace_period
```

Example: job scheduled at 02:00, expected 5 minutes, grace 30 minutes.
Alert fires at 02:35 if no completion ping received.

### Deduplication

Store the window start time in each alert. Before sending, check:
```sql
SELECT id FROM alerts
WHERE job_id = ? AND window_start = ? AND type = 'missed'
LIMIT 1
```

If found, skip. Prevents alert spam on restart or missed cleanup.

## Express Route Pattern

```typescript
// POST /ping/:jobId/start
router.post('/:jobId/start', validateApiKey, async (req, res) => {
  const job = await db.getJob(req.params.jobId);
  if (!job) return res.status(404).json({ error: 'Job not found' });

  const execution = await db.createExecution({
    jobId: job.id,
    startedAt: new Date().toISOString(),
    status: 'running',
  });

  await db.updateJobStatus(job.id, 'running');

  return res.json({ ok: true, executionId: execution.id });
});

// POST /ping/:jobId/complete
router.post('/:jobId/complete', validateApiKey, async (req, res) => {
  const { executionId, exitCode } = req.body;
  const execution = await db.getExecution(executionId);

  const durationS = Math.round(
    (Date.now() - new Date(execution.startedAt).getTime()) / 1000
  );

  await db.updateExecution(executionId, {
    completedAt: new Date().toISOString(),
    status: 'completed',
    durationS,
    exitCode: exitCode ?? 0,
  });

  await db.updateJobStatus(execution.jobId, 'ok');

  return res.json({ ok: true, duration_s: durationS });
});
```

## Alert Engine Pattern

```typescript
// Runs every minute via node-cron
async function checkMissedJobs(): Promise<void> {
  const jobs = await db.getActiveJobs();
  const now = new Date();

  for (const job of jobs) {
    if (job.status === 'paused') continue;

    const lastWindow = getLastScheduledRun(job.schedule, now);
    const alertTime = addMinutes(lastWindow, job.expectedDurM + job.gracePeriodM);

    if (now < alertTime) continue; // not yet overdue
    if (job.status === 'completed' || job.status === 'running') continue;

    // Check deduplication
    const alreadyAlerted = await db.hasAlert(job.id, lastWindow);
    if (alreadyAlerted) continue;

    await dispatchAlert(job, lastWindow, 'missed');
  }
}
```

## Cron Expression Parsing

Use `cron-parser` to find the last scheduled run:

```typescript
import { parseExpression } from 'cron-parser';

function getLastScheduledRun(cronExpr: string, now: Date): Date {
  const interval = parseExpression(cronExpr, { currentDate: now });
  return interval.prev().toDate();
}
```

## Webhook Payload Format

```json
{
  "event": "missed",
  "job": {
    "id": "job_a1b2c3",
    "name": "nightly-postgres",
    "schedule": "0 2 * * *"
  },
  "window": {
    "scheduledAt": "2026-03-20T02:00:00Z",
    "alertFiredAt": "2026-03-20T02:35:00Z",
    "gracePeriodMinutes": 30
  },
  "dashboardUrl": "http://localhost:4000/jobs/job_a1b2c3"
}
```

## Email Template

Subject: `[backup-monitor] MISSED: nightly-postgres`

Body: Plain text. Include job name, schedule, last successful run, dashboard link.

## Dependencies

| Package | Purpose |
|---|---|
| `cron-parser` | Parse cron expressions, find last/next run |
| `node-cron` | Run alert engine on schedule |
| `nodemailer` | Send email alerts |
| `better-sqlite3` | SQLite storage |

Related Skills

Skill: Uptime Monitoring

7
from heldernoid/agentic-build-templates

## Overview

Skill: Status Page

7
from heldernoid/agentic-build-templates

## Overview

Skill: unit-conversion

7
from heldernoid/agentic-build-templates

## Overview

Skill: recipe-scaler

7
from heldernoid/agentic-build-templates

## Overview

reading-list

7
from heldernoid/agentic-build-templates

Operate the reading-list API to save, manage, tag, search, and export articles.

email-digest

7
from heldernoid/agentic-build-templates

Configure, test, and troubleshoot the reading-list daily email digest delivered via nodemailer.

websocket-realtime

7
from heldernoid/agentic-build-templates

Use the WebSocket connection in poll-builder to receive live vote updates. Use when you need to stream real-time poll results, monitor a poll for new votes, or build a live dashboard. Triggers include "live results", "real-time updates", "stream votes", "watch poll", or "WebSocket".

poll-builder

7
from heldernoid/agentic-build-templates

Self-hosted poll creation tool with real-time results. Use when you need to create a poll, check vote counts, close a poll, export results, or get the shareable link for a poll. Triggers include "create poll", "vote", "poll results", "survey", "collect votes", "share poll", or any task involving polling or voting.

Skill: personal-finance

7
from heldernoid/agentic-build-templates

## Overview

Skill: csv-import

7
from heldernoid/agentic-build-templates

## Overview

Skill: Syntax Highlighting

7
from heldernoid/agentic-build-templates

## Purpose

Skill: Pastebin Core

7
from heldernoid/agentic-build-templates

## Purpose