Stale Backup Detection: Last Backup Was a Month Ago
The backup job runs every night and exits 0. But the last time it actually wrote a valid file was a month ago. Learn how to detect stale backups by checking backup age and get alerts before you need to restore.
The Problem: Backup "Runs" but Isn't Fresh
Cron runs the backup script. The script exits successfully. But the backup file hasn't been updated in weeks—maybe the script is writing to the wrong path, or a step failed silently and the file is old. You only find out when you need to restore.
- Backup script runs but writes to a path that changed; real backup is elsewhere and old
- First step fails; script still exits 0 and pings "success"
- Disk full or permission error after the last good run; no new file, nobody checks date
- Last good backup was a month ago—you discover it during an incident
A simple success ping isn't enough. You need to verify that the backup file (or artifact) was actually updated recently.
Solution: Send Backup Age (modified_at) and Validate It
After creating or updating the backup, read the file's modification time (or your backup tool's completion time). Send that as part of the ping payload. In DeadManPing, set a validation rule: e.g. backup must be no older than 25 hours (or 2x your backup interval). If the backup is stale, validation fails and you get an alert.
Bash: File mtime as Unix timestamp
#!/bin/bash
BACKUP_FILE="/backups/db-$(date +%Y%m%d).sql.gz"
/path/to/backup.sh -o "$BACKUP_FILE"
# Get last modified time (Unix timestamp) and size
MTIME=$(stat -c %Y "$BACKUP_FILE")
SIZE=$(stat -c %s "$BACKUP_FILE")
# Ping with payload; in DeadManPing set rule: modified_at within last 25 hours
curl -X POST "https://deadmanping.com/api/ping/backup-daily?modified_at=$MTIME&file_size=$SIZE"Python: Send ISO date or timestamp
import os
from datetime import datetime
import urllib.request
backup_path = "/backups/db-latest.sql.gz"
run_backup(backup_path)
mtime = os.path.getmtime(backup_path)
# Send as Unix timestamp; DeadManPing can validate max age
url = f"https://deadmanping.com/api/ping/backup-daily?modified_at={int(mtime)}&file_size={os.path.getsize(backup_path)}"
urllib.request.urlopen(url)Node.js: Backup age in seconds
const fs = require('fs');
const path = '/backups/db-latest.sql.gz';
await runBackup(path);
const stat = fs.statSync(path);
const modifiedAt = Math.floor(stat.mtimeMs / 1000);
const fileSize = stat.size;
await fetch(
`https://deadmanping.com/api/ping/backup-daily?modified_at=${modifiedAt}&file_size=${fileSize}`,
{ method: 'POST' }
);Configure Max Age in DeadManPing
In the monitor's payload validation rules, use modified_at: "must be within last X hours" (or "max age" in seconds). If the backup file is older than that, the ping fails validation and you get an alert—so you know the last good backup is too old before you need to restore.
Combine with file_size (or file_size_mb) so you also catch empty or zero-byte backups. One ping with file metadata; the dashboard does the rest.
Don't Discover a Stale Backup When You Restore
DeadManPing payload validation checks backup age and size. Add one ping with modified_at and optional file_size; get alerts when the backup is stale or empty.
Related Articles
Learn more about cron job monitoring and troubleshooting:
Backup Monitoring Service
Backup monitoring that doesn't touch your execution.
Detect Empty Backup File
How to detect when backup files are empty or zero bytes.
Verify Backup File Size
How to verify backup file sizes are within expected ranges.
Dead Man Switch for Backups
Implement dead man switch monitoring for backup jobs to detect failures immediately.