From 4816980cbcaaf54fedb23da8b4061e86a53df91c Mon Sep 17 00:00:00 2001 From: Mahmoud Yasser Date: Thu, 24 Dec 2020 23:06:56 +0200 Subject: [PATCH] Update index.ts i'm using here clusters which will boost the performance of the API to use all all the cpu's cores when you upload your API on the cloud so you turn the setupServer to true when you run your API on the cloud but if you gonna develop it and use it in your PC you should turn it off, cause it will use all your cpu's cores and then the PC will slow down --- src/index.ts | 108 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 100 insertions(+), 8 deletions(-) diff --git a/src/index.ts b/src/index.ts index 5fd2ef3..9cb5c7d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,17 +1,109 @@ import 'reflect-metadata'; import { createConnection } from 'typeorm'; +import chalk from 'chalk'; + +import cluster from 'cluster'; +const numCores = require('os').cpus().length; import logger from './config/logger'; import app from './config/express'; const PORT = process.env.PORT || 5000; -createConnection() - .then(() => { - logger.info('database connection created'); - app.listen(PORT, () => { - logger.info(`Server running at ${PORT}`); +// Handle uncaught exceptions +process.on('uncaughtException', (uncaughtExc) => { + // Won't execute + console.log(chalk.bgRed('UNCAUGHT EXCEPTION! 💥 Shutting down...')); + console.log('uncaughtException Err::', uncaughtExc); + console.log('uncaughtException Stack::', JSON.stringify(uncaughtExc.stack)); + process.exit(1); +}); + +// Setup number of worker processes to share port which will be defined while setting up server +const workers = []; +const setupWorkerProcesses = () => { + // Read number of cores on system + console.log(`Master cluster setting up ${numCores} workers`); + + // Iterate on number of cores need to be utilized by an application + // Current example will utilize all of them + for (let i = 0; i < numCores; i++) { + // Creating workers and pushing reference in an array + // these references can be used to receive messages from workers + workers.push(cluster.fork()); + + // Receive messages from worker process + workers[i].on('message', function (message) { + console.log(message); + }); + } + + // Process is clustered on a core and process id is assigned + cluster.on('online', function (worker) { + console.log(`Worker ${worker.process.pid} is listening`); + }); + + // If any of the worker process dies then start a new one by simply forking another one + cluster.on('exit', function (worker, code, signal) { + console.log( + `Worker ${worker.process.pid} died with code: ${code}, and signal: ${signal}` + ); + console.log('Starting a new worker'); + cluster.fork(); + workers.push(cluster.fork()); + // Receive messages from worker process + workers[workers.length - 1].on('message', function (message) { + console.log(message); }); - }) - .catch((error: Error) => { - logger.info(`Database connection failed with error ${error}`); }); +}; + +// Setup an express server and define port to listen all incoming requests for this application +const setUpExpress = () => { + createConnection() + .then(() => { + logger.info('database connection created'); + app.listen(PORT, () => { + logger.info(`Server running at ${PORT}`); + }); + }) + .catch((error: Error) => { + logger.info(`Database connection failed with error ${error}`); + }); + + // In case of an error + app.on('error', (appErr, appCtx) => { + console.error('app error', appErr.stack); + console.error('on url', appCtx.req.url); + console.error('with headers', appCtx.req.headers); + }); + + // Handle unhandled promise rejections + process.on('unhandledRejection', (err) => { + console.log(chalk.bgRed('UNHANDLED REJECTION! 💥 Shutting down...')); + console.log(err.name, err.message); + // Close server & exit process + server.close(() => { + process.exit(1); + }); + }); + + process.on('SIGTERM', () => { + console.log('👋 SIGTERM RECEIVED. Shutting down gracefully'); + server.close(() => { + console.log('💥 Process terminated!'); + }); + }); +}; + +// Setup server either with clustering or without it +const setupServer = (isClusterRequired) => { + // If it is a master process then call setting up worker process + if (isClusterRequired && cluster.isMaster) { + setupWorkerProcesses(); + } else { + // Setup server configurations and share port address for incoming requests + setUpExpress(); + } +}; + +setupServer(true);