'use strict'
// @ts-check
const _ = require('lodash')
const process = require('process')
const cluster = require('cluster')
const Logger = require('@fizz.js/node-logger')
const Common = require('@fizz.js/node-common')
const ErrorReporter = require('@fizz.js/node-error-reporter')
const { ServerError } = require('@fizz.js/node-errors')
/**
*
*
* @class ClusterHandler
*/
class ClusterHandler {
/**
*
* @returns {cluster}
* @memberof ClusterHandler
*/
registerHandler() {
return cluster
.on('message', this.onMessage.bind(this))
.on('online', this.onOnline.bind(this))
.on('disconnect', this.onDisconnect.bind(this))
.on('exit', this.onExit.bind(this))
.on('listening', this.onListening.bind(this))
.on('setup', this.onSetup.bind(this))
.on('death', this.onDeath.bind(this))
}
/**
*
* @param {cluster.Worker} worker
* @param {any} message
* @param {net.Socket|net.Server} [handle=undefined]
* @returns {void}
* @memberof ClusterHandler
*/
onMessage(worker, message, handle = undefined) {
try {
if (!_.has(process.env, 'NODE_APP_INSTANCE')) {
return cluster.isMaster
? this.onMasterMessage(worker, message, handle)
: this.onWorkerMessage(worker, message, handle)
}
} catch (error) {
Logger.error(error)
throw error
}
}
/**
*
*
* @param {cluster.Worker} worker
* @param {any} message
* @param {net.Socket|net.Server} [handle=undefined]
* @returns {void}
* @memberof ClusterHandler
*/
onWorkerMessage(worker, message, handle = undefined) {
try {
Logger.info(`WORKER ON MESSAGE: ${Common.toJSON(message)} PID: ${_.get(worker, 'id')}`)
} catch (error) {
Logger.error(error)
throw error
}
}
/**
*
*
* @param {cluster.Worker} worker
* @param {any} message
* @param {net.Socket|net.Server} [handle=undefined]
* @returns {void}
* @memberof ClusterHandler
*/
onMasterMessage(worker, message, handle = undefined) {
try {
Logger.info(`MASTER ON MESSAGE: ${Common.toJSON(message)} PID: ${_.get(worker, 'id')}`)
} catch (error) {
Logger.error(error)
throw error
}
}
/**
*
*
* @param {cluster.Worker} worker
* @returns {void}
* @memberof ClusterHandler
*/
onOnline(worker) {
try {
Logger.info(`WORKER IS NOW ONLINE ${_.get(worker, 'id')} ${_.get(worker, 'process.pid')}`)
} catch (error) {
Logger.error(error)
throw error
}
}
/**
*
* @param {cluster.Worker} worker
* @param {cluster.Address} address
* @returns {void}
* @memberof ClusterHandler
*/
async onListening(worker, address) {
try {
Logger.debug(
`WORKER ON LISTENING [ID: ${_.get(worker, 'id')}] [ADDRESS: ${_.get(address, 'address')}] [PORT: ${_.get(
address,
'port'
)}] [TYPE: ${_.get(address, 'addressType')}]`
)
} catch (error) {
Logger.error(error)
}
}
/**
*
*
* @param {cluster.ClusterSettings} settings
* @returns {void}
* @memberof ClusterHandler
*/
async onSetup(settings) {
try {
Logger.debug(
`WORKER ON SETTING UP ARGS: [${_.get(settings, 'args')}] [EXEC: ${_.get(settings, 'exec')}] [ARGV: ${_.get(
settings,
'execArgv'
)}] [SILENT: ${_.get(settings, 'silent')}]`
)
} catch (error) {
Logger.error(error)
}
}
/**
*
*
* @param {cluster.Worker} worker
* @param {number} code
* @param {string} sig
* @returns {void}
* @memberof ClusterHandler
*/
async onExit(worker, code, sig) {
try {
await this.onError(`WORKER IS EXITED pid: ${_.get(worker, 'id')} code: ${code} sig: ${sig}`)
} catch (error) {
Logger.error(error)
}
}
/**
*
*
* @param {cluster.Worker} worker
* @returns {void}
* @memberof ClusterHandler
*/
async onDisconnect(worker) {
try {
await this.onError(`WORKER IS DISCONNECTED PID: ${_.get(worker, 'id')}`)
} catch (error) {
Logger.error(error)
}
}
/**
*
* @deprecated
* @param {cluster.Worker} worker
* @returns {void}
* @memberof ClusterHandler
*/
async onDeath(worker) {
try {
await this.onError(`WORKER ON DEATH PID: ${_.get(worker, 'id')}`, _.get(process, 'env.NODE_ENV') === 'production')
} catch (error) {
Logger.error(error)
}
}
/**
*
*
* @param {cluster.Worker} worker
* @param {boolean} [recovery=false]
* @returns {void}
* @memberof ClusterHandler
*/
async onError(message, recovery = false) {
try {
const error = new ServerError(message)
await ErrorReporter.handleError(error, 'warn', false).catch(e => Logger.noop())
} catch (error) {
Logger.error(error)
} finally {
if (recovery) {
this.recover()
}
}
}
/**
*
*
* @returns {cluster.Worker}
* @memberof ClusterHandler
*/
recover() {
return cluster.fork()
}
}
module.exports = new ClusterHandler()
Source