Skip to content
Snippets Groups Projects
Commit d30a84a8 authored by michael.minelli's avatar michael.minelli
Browse files

Add multiple process management

parent 7ce41f94
No related branches found
No related tags found
No related merge requests found
import cluster, { Worker } from 'node:cluster';
import WorkerRole from './WorkerRole';
import os from 'os';
import ClusterStrategy from './ClusterStrategy';
import WorkerPool from './WorkerPool';
import logger from '../shared/logging/WinstonLogger';
/*
This class create a cluster of workers by following the strategy (array of WorkerPool) given in the constructor.
*/
class ClusterManager {
public static readonly CORES = os.cpus().length;
private workers: { [pid: number]: WorkerRole; } = [];
constructor(private strategy: ClusterStrategy) {}
private getWorkerPool(role: WorkerRole): WorkerPool | undefined {
return this.strategy.find(elem => elem.role === role);
}
private runPrimary() {
logger.info(`Number of cores: ${ ClusterManager.CORES }`);
logger.info(`Primary process is running`);
this.strategy.forEach(workerPool => {
for ( let i = 0 ; i < workerPool.quantity ; i += 1 ) {
const worker = cluster.fork({ role: workerPool.role });
this.workers[worker.process.pid] = workerPool.role;
}
});
// Listen for dying workers and restart them
cluster.on('exit', (worker: Worker, code: number) => {
logger.info(`Worker ${ worker.process.pid } exited with code ${ code }`);
const workerRole = this.workers[worker.process.pid];
const workerPool = this.getWorkerPool(workerRole);
if ( workerPool && workerPool.restartOnFail ) {
const newWorker = cluster.fork({ role: workerRole });
this.workers[newWorker.process.pid] = workerPool.role;
}
delete this.workers[worker.process.pid];
});
}
private runWorker() {
const workerRole = Number(process.env['role']);
const workerPool = this.getWorkerPool(workerRole);
if ( workerPool ) {
workerPool.loadTask().run();
} else {
logger.warn(`Process task not found for role ${ workerRole }`);
}
}
run() {
if ( cluster.isPrimary ) {
this.runPrimary();
} else {
this.runWorker();
}
}
}
export default ClusterManager;
import WorkerPool from './WorkerPool';
type ClusterStrategy = Array<WorkerPool>
export default ClusterStrategy;
\ No newline at end of file
import WorkerRole from './WorkerRole';
import WorkerTask from './WorkerTask';
/*
This interface describe a pool of workers.
*/
interface WorkerPool {
role: WorkerRole,
quantity: number,
restartOnFail: boolean,
loadTask: () => WorkerTask, //This is a function for lazy load the task (only loaded on function call)
}
export default WorkerPool;
enum WorkerRole {
None = 0,
API = 1
}
export default WorkerRole;
interface WorkerTask {
run(): void;
}
export default WorkerTask;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment