typescriptadvanced

Cluster Worker Pool Pattern

Distribute CPU-intensive tasks across worker processes with automatic restart and load balancing.

typescript
import cluster from 'cluster';
import os from 'os';
import http from 'http';

const NUM_WORKERS = os.cpus().length;

if (cluster.isPrimary) {
  console.log(`Primary ${process.pid} starting ${NUM_WORKERS} workers`);

  const workers: Map<number, ReturnType<typeof cluster.fork>> = new Map();

  // Fork workers
  for (let i = 0; i < NUM_WORKERS; i++) {
    const worker = cluster.fork();
    workers.set(worker.id, worker);
  }

  // Auto-restart on crash
  cluster.on('exit', (worker, code, signal) => {
    console.log(`Worker ${worker.process.pid} died (${signal || code})`);
    workers.delete(worker.id);

    if (code !== 0) {
      console.log('Starting replacement worker...');
      const newWorker = cluster.fork();
      workers.set(newWorker.id, newWorker);
    }
  });

  // Graceful shutdown
  process.on('SIGTERM', () => {
    console.log('Shutting down all workers...');
    for (const [, worker] of workers) {
      worker.send('shutdown');
    }
    setTimeout(() => process.exit(0), 5000);
  });

  // Health check
  setInterval(() => {
    console.log(`Active workers: ${workers.size}`);
  }, 30000);

} else {
  // Worker process
  const server = http.createServer((req, res) => {
    // Simulate CPU work
    if (req.url === '/heavy') {
      let sum = 0;
      for (let i = 0; i < 1e7; i++) sum += Math.random();
      res.end(`Worker ${process.pid}: ${sum.toFixed(2)}`);
    } else {
      res.end(`Worker ${process.pid} ready`);
    }
  });

  server.listen(3000);
  console.log(`Worker ${process.pid} listening on 3000`);

  process.on('message', (msg) => {
    if (msg === 'shutdown') {
      server.close(() => process.exit(0));
    }
  });
}

Sponsored

Railway

Use Cases

  • Multi-core CPU utilization
  • Zero-downtime worker restarts
  • High-throughput API servers

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.