Heartbeat
Create heartbeat monitors for job and cron health checks
The Heartbeat resource creates monitors that expect regular "pings" from your jobs, cron tasks, or scheduled processes.
Example Usage
Basic Heartbeat
import * as betteruptime from "@pulumi-contrib/better-uptime";
const heartbeat = new betteruptime.Heartbeat("backup-job", {
name: "Database Backup",
period: 86400, // 24 hours
grace: 3600, // 1 hour grace period
});
// Export the heartbeat URL to ping
export const heartbeatUrl = heartbeat.url;Cron Job Heartbeat
const cronHeartbeat = new betteruptime.Heartbeat("daily-sync", {
name: "Daily Data Sync",
period: 86400, // Every 24 hours
grace: 1800, // 30 minute grace period
call: true,
sms: true,
email: true,
});Short-Interval Heartbeat
const frequentJob = new betteruptime.Heartbeat("health-check-job", {
name: "Health Check Job",
period: 300, // Every 5 minutes
grace: 60, // 1 minute grace period
});Heartbeat with Policy
import * as betteruptime from "@pulumi-contrib/better-uptime";
const policy = new betteruptime.Policy("ops-team", {
name: "Operations Team",
});
const criticalJob = new betteruptime.Heartbeat("critical-batch", {
name: "Critical Batch Process",
period: 3600, // Hourly
grace: 300, // 5 minutes
policyId: policy.id,
call: true,
sms: true,
});Heartbeat Group
const group = new betteruptime.HeartbeatGroup("batch-jobs", {
name: "Batch Processing Jobs",
});
const heartbeat1 = new betteruptime.Heartbeat("job1", {
name: "ETL Job 1",
period: 43200, // 12 hours
grace: 1800,
heartbeatGroupId: group.id,
});
const heartbeat2 = new betteruptime.Heartbeat("job2", {
name: "ETL Job 2",
period: 43200,
grace: 1800,
heartbeatGroupId: group.id,
});Argument Reference
Required Arguments
name(String) - Name of the heartbeat monitorperiod(Number) - Expected period between pings in seconds
Optional Arguments
grace(Number) - Grace period in seconds before alerting. Default: 0call(Boolean) - Enable phone call notifications. Default: falsesms(Boolean) - Enable SMS notifications. Default: falseemail(Boolean) - Enable email notifications. Default: truepush(Boolean) - Enable push notifications. Default: trueheartbeatGroupId(Number) - Heartbeat group IDpolicyId(Number) - Escalation policy IDpaused(Boolean) - Whether the heartbeat is paused. Default: falsesort_index(Number) - Sort index for ordering
Attribute Reference
id(String) - The heartbeat IDurl(String) - The unique URL to pingstatus(String) - Current heartbeat status (up, down, paused)createdAt(String) - Creation timestampupdatedAt(String) - Last update timestamplastPingAt(String) - Last successful ping timestamp
Using Heartbeat URLs
In Shell Scripts
#!/bin/bash
# Your backup script
# Perform backup
pg_dump mydb > backup.sql
# Ping heartbeat on success
curl -fsS --retry 3 "https://uptime.betterstack.com/api/v1/heartbeat/xxx"In Python
import requests
def backup_job():
try:
# Perform backup
perform_backup()
# Ping heartbeat
requests.get("https://uptime.betterstack.com/api/v1/heartbeat/xxx")
except Exception as e:
print(f"Backup failed: {e}")
# Don't ping on failure - will trigger alertIn Node.js
const https = require('https');
async function cronJob() {
try {
await performTask();
// Ping heartbeat
https.get('https://uptime.betterstack.com/api/v1/heartbeat/xxx');
} catch (error) {
console.error('Job failed:', error);
// Missing ping will trigger alert
}
}In Docker
FROM alpine:latest
# Install curl
RUN apk add --no-cache curl
# Your cron job
COPY backup.sh /backup.sh
RUN chmod +x /backup.sh
# Add heartbeat ping
RUN echo "*/5 * * * * /backup.sh && curl -fsS https://uptime.betterstack.com/api/v1/heartbeat/xxx" > /etc/crontabs/root
CMD ["crond", "-f"]Best Practices
Period and Grace Configuration
| Job Frequency | Period | Grace | Use Case |
|---|---|---|---|
| Every 5 min | 300s | 60s | Frequent health checks |
| Hourly | 3600s | 300s | Regular maintenance |
| Every 6 hours | 21600s | 1800s | Periodic sync jobs |
| Daily | 86400s | 3600s | Daily backups |
| Weekly | 604800s | 7200s | Weekly reports |
Error Handling
// Only ping on success
const heartbeat = new betteruptime.Heartbeat("reliable-job", {
name: "Data Processing",
period: 3600,
grace: 300,
call: true, // Alert immediately via call
});
// In your job script:
// curl "$HEARTBEAT_URL" || exit 0 # Don't fail job if ping failsMonitoring Multiple Environments
// Production heartbeat
const prodHeartbeat = new betteruptime.Heartbeat("prod-backup", {
name: "Production Backup",
period: 86400,
grace: 1800,
call: true,
sms: true,
});
// Staging heartbeat
const stagingHeartbeat = new betteruptime.Heartbeat("staging-backup", {
name: "Staging Backup",
period: 86400,
grace: 3600, // More grace for staging
email: true,
});Grouped Heartbeats
// Create a group for related jobs
const group = new betteruptime.HeartbeatGroup("etl-pipeline", {
name: "ETL Pipeline Jobs",
});
const steps = ["extract", "transform", "load"].map((step, i) =>
new betteruptime.Heartbeat(`etl-${step}`, {
name: `ETL ${step.toUpperCase()}`,
period: 7200, // 2 hours
grace: 600,
heartbeatGroupId: group.id,
sortIndex: i,
})
);Common Patterns
Database Backup Monitoring
const dbBackup = new betteruptime.Heartbeat("postgres-backup", {
name: "PostgreSQL Backup",
period: 86400, // Daily
grace: 3600, // 1 hour grace
call: true,
sms: true,
});
// In backup script:
// pg_dump db | gzip > backup.gz && curl "$HEARTBEAT_URL"Cron Job Monitoring
const cronJob = new betteruptime.Heartbeat("report-generation", {
name: "Daily Report Generation",
period: 86400,
grace: 1800,
});
// Crontab:
// 0 2 * * * /usr/local/bin/generate-report.sh && curl "$HEARTBEAT_URL"API Scheduled Task
const scheduledTask = new betteruptime.Heartbeat("cleanup-task", {
name: "Cleanup Old Records",
period: 21600, // Every 6 hours
grace: 900, // 15 minutes
});
// In your API:
// schedule.every(6).hours.do(cleanup_and_ping)Import
Heartbeats can be imported using their ID:
pulumi import better-uptime:index/heartbeat:Heartbeat example 123456Troubleshooting
Heartbeat Not Receiving Pings
Causes:
- Incorrect URL
- Network/firewall issues
- Job failing before ping
Solution:
- Verify heartbeat URL is correct
- Test with curl manually
- Add logging to job
# Debug heartbeat ping
curl -v "https://uptime.betterstack.com/api/v1/heartbeat/xxx"False Alerts
Cause: Grace period too short for job variability
Solution:
// Increase grace period for variable jobs
const variableJob = new betteruptime.Heartbeat("variable", {
name: "Variable Duration Job",
period: 3600,
grace: 1800, // 50% of period as grace
});Missing Heartbeat Groups
Error: "Heartbeat group not found"
Solution: Ensure group is created before heartbeats:
const group = new betteruptime.HeartbeatGroup("group", {
name: "My Group",
});
const heartbeat = new betteruptime.Heartbeat("hb", {
name: "Heartbeat",
period: 3600,
heartbeatGroupId: group.id,
}, { dependsOn: [group] });