A production-grade backend service that monitors remote devices (solar farms, weather stations, etc.) and triggers escalating alerts when a device stops sending heartbeats.
Built with Python + Django + Redis.
- A device registers a monitor with a timeout (e.g. 60 seconds)
- Redis starts a countdown (TTL key)
- The device sends heartbeats to reset the timer
- If no heartbeat arrives before the timer hits zero, Redis fires an expiry event
- A background listener catches the event and fires escalating alerts
- A maintenance technician can pause monitoring to avoid false alarms
- Python 3.10+
- Redis server
- pip
1. Clone the repository
git clone https://github.com/KingJoe-14/Pulse-Check-API.git
cd Pulse-Check-API2. Create and activate a virtual environment
python -m venv venv
source venv/bin/activate3. Install dependencies
pip install -r requirements.txt4. Set up your environment variables
Create a .env file in the root directory:
touch .envThen add the following variables to the .env file:
SECRET_KEY=your-secret-key-here
DEBUG=True
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_DB=0
| Variable | Description | Default |
|---|---|---|
SECRET_KEY |
Django secret key | required |
DEBUG |
Debug mode | True |
REDIS_HOST |
Redis server host | 127.0.0.1 |
REDIS_PORT |
Redis server port | 6379 |
REDIS_DB |
Redis database number | 0 |
5. Start Redis
sudo service redis-server start6. Enable Redis keyspace notifications
redis-cli config set notify-keyspace-events Ex7. Run database-free check
python manage.py checkYou need two terminals running simultaneously:
Terminal 1 — API server
python manage.py runserverTerminal 2 — Keyspace listener
python manage.py start_listenerPOST /monitors/
Registers a new device monitor and starts the countdown timer.
Request body:
{
"id": "device-123",
"timeout": 60,
"alert_email": "admin@critmon.com"
}Responses:
| Status | Description |
|---|---|
| 201 | Monitor created successfully |
| 400 | Missing or invalid fields |
| 409 | Monitor with this ID already exists |
Example response (201):
{
"message": "Monitor for device-123 created successfully",
"monitor": {
"id": "device-123",
"timeout": 60,
"alert_email": "admin@critmon.com",
"status": "active",
"created_at": "2026-06-06T19:37:30.260117+00:00"
}
}POST /monitors/{id}/heartbeat/
Resets the countdown timer. Automatically unpauses a paused monitor.
No request body needed.
Responses:
| Status | Description |
|---|---|
| 200 | Timer reset successfully |
| 404 | Monitor not found |
| 400 | Monitor is down — use /recover to resume |
Example response (200):
{
"id": "device-123",
"status": "active",
"message": "Heartbeat received — timer reset",
"updated_at": "2026-06-06T19:45:00.000000+00:00"
}POST /monitors/{id}/pause/
Freezes the timer completely. No alerts will fire while paused. Sending a heartbeat automatically resumes the monitor.
No request body needed.
Responses:
| Status | Description |
|---|---|
| 200 | Monitor paused successfully |
| 400 | Monitor is already paused or is down |
| 404 | Monitor not found |
Example response (200):
{
"id": "device-123",
"status": "paused",
"message": "Monitor paused — no alerts will fire",
"updated_at": "2026-06-06T19:50:00.000000+00:00"
}GET /monitors/
Returns all registered monitors and their current status.
Example response (200):
[
{
"id": "device-123",
"timeout": "60",
"alert_email": "admin@critmon.com",
"status": "active",
"created_at": "2026-06-06T19:37:30.260117+00:00",
"updated_at": "2026-06-06T19:45:00.000000+00:00"
}
]GET /monitors/{id}/
Returns a single monitor by ID.
Responses:
| Status | Description |
|---|---|
| 200 | Monitor found |
| 404 | Monitor not found |
Example response (200):
{
"id": "device-123",
"timeout": "60",
"alert_email": "admin@critmon.com",
"status": "active",
"created_at": "2026-06-06T19:37:30.260117+00:00",
"updated_at": "2026-06-06T19:45:00.000000+00:00"
}POST /monitors/{id}/recover/
Recovers a down monitor back to active state. Restarts the timer and
clears all backoff alert keys. Only works when monitor status is down.
No request body needed.
Responses:
| Status | Description |
|---|---|
| 200 | Monitor recovered successfully |
| 400 | Monitor is not down |
| 404 | Monitor not found |
Example response (200):
{
"id": "device-123",
"status": "active",
"message": "Monitor device-123 recovered — timer restarted",
"updated_at": "2026-06-09T14:19:27.970093+00:00"
}DELETE /monitors/{id}/
Permanently deletes a monitor and stops all associated timers and alerts. Works regardless of monitor status (active, paused, or down).
No request body needed.
Responses:
| Status | Description |
|---|---|
| 200 | Monitor deleted successfully |
| 404 | Monitor not found |
Example response (200):
{
"message": "Monitor device-123 deleted successfully"
}When a device misses its heartbeat the system fires three escalating alerts logged to the listener console:
| Alert | Severity | When |
|---|---|---|
| Alert 1 | WARNING | Immediately when timer expires |
| Alert 2 | URGENT | 30 seconds after Alert 1 |
| Alert 3 | CRITICAL | 90 seconds after Alert 2 |
Example alert output:
{"ALERT": "Device device-123 is down!", "severity": "WARNING", "email": "admin@critmon.com", "time": "2026-06-06T21:13:49.500142+00:00"}
{"ALERT": "Device device-123 is still down!", "severity": "URGENT", "email": "admin@critmon.com", "time": "2026-06-06T21:14:19.578988+00:00"}
{"ALERT": "Device device-123 is still down!", "severity": "CRITICAL", "email": "admin@critmon.com", "time": "2026-06-06T21:15:49.612045+00:00"}Alerts stop escalating as soon as the device sends a heartbeat again.
Instead of firing a single alert when a device goes down, the system escalates notifications with increasing urgency over time.
A single alert is easy to miss. In a critical infrastructure context (solar farms, unmanned weather stations), a missed alert could mean hours of downtime before anyone responds. Escalating alerts ensure that:
- A first responder sees the WARNING immediately
- If unacknowledged, the URGENT alert creates pressure to act
- The CRITICAL alert signals a serious outage requiring immediate deployment
Redis backoff keys with expiring TTLs drive the escalation. Each alert schedules the next one by setting a new key with a delay. If the device recovers and sends a heartbeat, the backoff keys are cleared and escalation stops.
pulse-check-api/ ├── config/ # Django project settings │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── monitors/ # Core app │ ├── views.py # API endpoints │ ├── urls.py # URL routing │ ├── services/ │ │ ├── monitor_service.py # Register, heartbeat, pause, recover, delete logic │ │ └── alert_service.py # Alert firing and backoff │ └── management/commands/ │ └── start_listener.py # Redis keyspace event listener ├── redis_client/ │ └── client.py # Redis singleton ├── .env # Environment variables (not committed) ├── requirements.txt └── manage.py
- ✅ Repository is public
- ✅ No
node_modules,.env, or sensitive files committed - ✅ Server starts with
python manage.py runserver - ✅ Architecture diagram included
- ✅ Original instructions replaced with this README
- ✅ All endpoints documented with example requests
- ✅ Multiple meaningful commits