KyoMel / Yogyakarta, Indonesia

Term 164164 / 344

The Heartbeat (Distributed System)

Month
February 2026
Day
3
Source
2026/feb-term.md

Definition:

The Heartbeat is a pattern in distributed systems where nodes (servers, services, or processes) send periodic signals (heartbeats) to indicate they are alive and functioning properly. If a heartbeat stops, other nodes in the system assume the silent node has failed and take appropriate action (like routing traffic elsewhere or triggering failover).

Key Concept:

  • Periodic Signal: “I’m alive!” message sent at regular intervals
  • Health Check: Proves the node is responsive and working
  • Failure Detection: Absence of heartbeat indicates failure
  • Automated Response: System reacts without human intervention

Example:

Web Server Cluster

                    ┌─────────────────┐
                    │  Load Balancer  │
                    │  (HAProxy)      │
                    └────────┬────────┘
                             │
          ┌──────────────────┼──────────────────┐
          │                  │                  │
    ┌─────▼─────┐      ┌─────▼─────┐     ┌─────▼─────┐
    │ Server 1  │      │ Server 2  │     │ Server 3  │
    │ (Node)    │      │ (Node)    │     │ (Node)    │
    └───────────┘      └───────────┘     └───────────┘

Each server sends heartbeat to load balancer every 3 seconds.
Load balancer expects heartbeat within 10 seconds (3 missed = dead).

Heartbeat Implementation

// server.js - Web Server with Heartbeat

const express = require('express');
const axios = require('axios');

const app = express();
const SERVER_ID = process.env.SERVER_ID || 'server-1';
const SERVER_PORT = process.env.PORT || 3000;
const LOAD_BALANCER_URL = 'http://load-balancer:8080';
const HEARTBEAT_INTERVAL = 3000; // 3 seconds

// Main application logic
app.get('/', (req, res) => {
  res.json({
    message: 'Hello from ' + SERVER_ID,
    timestamp: new Date().toISOString()
  });
});

// Health check endpoint (alternative to active heartbeat)
app.get('/health', (req, res) => {
  // Check if server is actually healthy
  const isHealthy = checkSystemHealth();

  if (isHealthy) {
    res.status(200).json({
      status: 'healthy',
      server: SERVER_ID,
      uptime: process.uptime(),
      memory: process.memoryUsage(),
      timestamp: Date.now()
    });
  } else {
    // Report unhealthy state
    res.status(503).json({
      status: 'unhealthy',
      server: SERVER_ID,
      error: 'System degraded'
    });
  }
});

function checkSystemHealth() {
  // Check critical components
  const memoryOK = process.memoryUsage().heapUsed < 500 * 1024 * 1024; // < 500MB
  const dbConnected = checkDatabaseConnection();
  const cpuOK = getCurrentCPU() < 90; // < 90% CPU

  return memoryOK && dbConnected && cpuOK;
}

// HEARTBEAT: Active push to load balancer
function sendHeartbeat() {
  const heartbeatData = {
    server_id: SERVER_ID,
    timestamp: Date.now(),
    status: 'alive',
    metrics: {
      cpu: getCurrentCPU(),
      memory: process.memoryUsage().heapUsed,
      requests_per_sec: getRequestRate(),
      response_time_ms: getAvgResponseTime()
    }
  };

  axios.post(`${LOAD_BALANCER_URL}/heartbeat`, heartbeatData)
    .then(response => {
      console.log(`✅ [${SERVER_ID}] Heartbeat sent at ${new Date().toISOString()}`);
    })
    .catch(error => {
      console.error(`❌ [${SERVER_ID}] Failed to send heartbeat:`, error.message);
    });
}

// Start heartbeat loop
setInterval(sendHeartbeat, HEARTBEAT_INTERVAL);
console.log(`🔄 [${SERVER_ID}] Heartbeat started (every ${HEARTBEAT_INTERVAL}ms)`);

// Start server
app.listen(SERVER_PORT, () => {
  console.log(`🚀 [${SERVER_ID}] Server running on port ${SERVER_PORT}`);

  // Send initial heartbeat
  sendHeartbeat();
});

// Graceful shutdown - send final heartbeat
process.on('SIGTERM', () => {
  console.log(`🛑 [${SERVER_ID}] Shutting down gracefully...`);

  // Notify load balancer we're going down
  axios.post(`${LOAD_BALANCER_URL}/shutdown`, {
    server_id: SERVER_ID,
    reason: 'graceful_shutdown'
  }).then(() => {
    process.exit(0);
  });
});

Keep reading