enhance: シャットダウン時、DB接続が切れたら確実に終了させる (MisskeyIO#159)

This commit is contained in:
まっちゃとーにゅ 2023-08-25 15:55:25 +09:00 committed by NoriDev
parent 569efb0b80
commit 4f07235eec
2 changed files with 30 additions and 18 deletions

View file

@ -4,6 +4,7 @@
*/ */
import { setTimeout } from 'node:timers/promises'; import { setTimeout } from 'node:timers/promises';
import process from 'node:process';
import { Global, Inject, Module } from '@nestjs/common'; import { Global, Inject, Module } from '@nestjs/common';
import * as Redis from 'ioredis'; import * as Redis from 'ioredis';
import { DataSource } from 'typeorm'; import { DataSource } from 'typeorm';
@ -118,5 +119,9 @@ export class GlobalModule implements OnApplicationShutdown {
async onApplicationShutdown(signal: string): Promise<void> { async onApplicationShutdown(signal: string): Promise<void> {
await this.dispose(); await this.dispose();
process.emitWarning('Misskey is shutting down', {
code: 'MISSKEY_SHUTDOWN',
detail: `Application received ${signal} signal`,
});
} }
} }

View file

@ -9,6 +9,7 @@
import cluster from 'node:cluster'; import cluster from 'node:cluster';
import { EventEmitter } from 'node:events'; import { EventEmitter } from 'node:events';
import process from 'node:process';
import chalk from 'chalk'; import chalk from 'chalk';
import Xev from 'xev'; import Xev from 'xev';
import Logger from '@/logger.js'; import Logger from '@/logger.js';
@ -29,6 +30,8 @@ const ev = new Xev();
//#region Events //#region Events
let isShuttingDown = false;
if (cluster.isPrimary && !envOption.disableClustering) { if (cluster.isPrimary && !envOption.disableClustering) {
// Listen new workers // Listen new workers
cluster.on('fork', worker => { cluster.on('fork', worker => {
@ -41,25 +44,22 @@ if (cluster.isPrimary && !envOption.disableClustering) {
}); });
// Listen for dying workers // Listen for dying workers
cluster.on('exit', (worker, code, signal?) => { cluster.on('exit', (worker, code, signal) => {
// Replace the dead worker, // Replace the dead worker,
// we're not sentimental // we're not sentimental
if (signal) { clusterLogger.error(chalk.red(`[${worker.id}] died (${signal || code})`));
switch (signal) { if (!isShuttingDown) cluster.fork();
case 'SIGINT': else clusterLogger.info(chalk.yellow('Worker respawn disabled because of shutdown'));
case 'SIGTERM': });
console.log(chalk.green(`[${worker.id}] exited by signal: ${signal}`));
break; process.on('SIGINT', () => {
default: logger.warn(chalk.yellow('Process received SIGINT'));
console.error(chalk.red(`[${worker.id}] killed by signal: ${signal}`)); isShuttingDown = true;
cluster.fork(); });
break;
} process.on('SIGTERM', () => {
} else if (code !== 0) { logger.warn(chalk.yellow('Process received SIGTERM'));
console.error(chalk.red(`[${worker.id}] exited with error code: ${code}`)); isShuttingDown = true;
} else {
console.log(chalk.green(`[${worker.id}] exited normally`));
}
}); });
} }
@ -78,7 +78,14 @@ process.on('uncaughtException', err => {
// Dying away... // Dying away...
process.on('exit', code => { process.on('exit', code => {
logger.info(`The process is going to exit with code ${code}`); logger.warn(chalk.yellow(`The process is going to exit with code ${code}`));
});
process.on('warning', warning => {
if ((warning as never)['code'] !== 'MISSKEY_SHUTDOWN') return;
logger.warn(chalk.yellow(`${warning.message}: ${(warning as never)['detail']}`));
for (const id in cluster.workers) cluster.workers[id]?.process.kill('SIGTERM');
process.exit();
}); });
//#endregion //#endregion