Skip to content

Instantly share code, notes, and snippets.

@Dante-101
Last active October 17, 2024 19:42
Show Gist options
  • Select an option

  • Save Dante-101/de2fbd5071bec0c0647f5c9fa1cfa179 to your computer and use it in GitHub Desktop.

Select an option

Save Dante-101/de2fbd5071bec0c0647f5c9fa1cfa179 to your computer and use it in GitHub Desktop.
Gist for graceful shutdown of workers
gracefulClusterShutdown = (signal: NodeJS.Signals) => async () => {
if (this.shutdownInProgress)
return
this.shutdownInProgress = true
this.hasCleanWorkerExit = true
log.info(`Got ${signal} on ${this.processStr}. Graceful shutdown start at ${new Date().toISOString()}`)
try {
if (cluster.isMaster) {
await this.shutdownWorkers(signal)
log.info(`${this.processStr} - worker shutdown successful`)
}
await this.stop() //stop yourself after the workers are shutdown if you are master
log.info(`${this.processStr} shutdown successful`)
logAndExit(this.hasCleanWorkerExit ? 0 : 1)
} catch (e) {
logAndExit(1)
}
}
shutdownWorkers = (signal: NodeJS.Signals) => {
return new Promise<void>((resolve, reject) => {
if (!cluster.isMaster) { return resolve() }
const wIds = Object.keys(cluster.workers)
if (wIds.length == 0) { return resolve() }
//Filter all the valid workers
const workers = wIds.map(id => cluster.workers[id]).filter(v => v) as cluster.Worker[]
let workersAlive = 0
let funcRun = 0
//Count the number of alive workers and keep looping until the number is zero.
const fn = () => {
++funcRun
workersAlive = 0
workers.forEach(worker => {
if (!worker.isDead()) {
++workersAlive
if (funcRun == 1)
//On the first execution of the function, send the received signal to all the workers
worker.kill(signal)
}
})
log.info(workersAlive + " workers alive")
if (workersAlive == 0) {
//Clear the interval when all workers are dead
clearInterval(interval)
return resolve()
}
}
const interval = setInterval(fn, 500)
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment