Graceful Shutdown (MisskeyIO#156)

---------

Co-authored-by: まっちゃとーにゅ <17376330+u1-liquid@users.noreply.github.com>
This commit is contained in:
riku6460 2023-08-22 21:42:21 +09:00 committed by GitHub
parent eaae8e6bea
commit daf429eb84
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 38 additions and 21 deletions

View File

@ -86,4 +86,4 @@ ENV MALLOC_CONF=background_thread:true,metadata_thp:auto,dirty_decay_ms:30000,mu
ENV NODE_ENV=production ENV NODE_ENV=production
HEALTHCHECK --interval=5s --retries=20 CMD ["/bin/bash", "/misskey/healthcheck.sh"] HEALTHCHECK --interval=5s --retries=20 CMD ["/bin/bash", "/misskey/healthcheck.sh"]
ENTRYPOINT ["/usr/bin/tini", "--"] ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["pnpm", "run", "migrateandstart"] CMD ["pnpm", "run", "migrateandstart:docker"]

View File

@ -18,11 +18,13 @@
"build": "pnpm build-pre && pnpm -r build && pnpm gulp", "build": "pnpm build-pre && pnpm -r build && pnpm gulp",
"build-storybook": "pnpm --filter frontend build-storybook", "build-storybook": "pnpm --filter frontend build-storybook",
"start": "pnpm check:connect && cd packages/backend && node ./built/boot/index.js", "start": "pnpm check:connect && cd packages/backend && node ./built/boot/index.js",
"start:docker": "pnpm check:connect && cd packages/backend && exec node ./built/boot/index.js",
"start:test": "cd packages/backend && cross-env NODE_ENV=test node ./built/boot/index.js", "start:test": "cd packages/backend && cross-env NODE_ENV=test node ./built/boot/index.js",
"init": "pnpm migrate", "init": "pnpm migrate",
"migrate": "cd packages/backend && pnpm migrate", "migrate": "cd packages/backend && pnpm migrate",
"check:connect": "cd packages/backend && pnpm check:connect", "check:connect": "cd packages/backend && pnpm check:connect",
"migrateandstart": "pnpm migrate && pnpm start", "migrateandstart": "pnpm migrate && pnpm start",
"migrateandstart:docker": "pnpm migrate && exec pnpm start:docker",
"gulp": "pnpm exec gulp build", "gulp": "pnpm exec gulp build",
"watch": "pnpm dev", "watch": "pnpm dev",
"dev": "node ./scripts/dev.mjs", "dev": "node ./scripts/dev.mjs",

View File

@ -29,6 +29,7 @@ const ev = new Xev();
//#region Events //#region Events
if (cluster.isPrimary && !envOption.disableClustering) {
// Listen new workers // Listen new workers
cluster.on('fork', worker => { cluster.on('fork', worker => {
clusterLogger.debug(`Process forked: [${worker.id}]`); clusterLogger.debug(`Process forked: [${worker.id}]`);
@ -40,12 +41,27 @@ cluster.on('online', worker => {
}); });
// Listen for dying workers // Listen for dying workers
cluster.on('exit', worker => { cluster.on('exit', (worker, code, signal?) => {
// Replace the dead worker, // Replace the dead worker,
// we're not sentimental // we're not sentimental
clusterLogger.error(chalk.red(`[${worker.id}] died :(`)); if (signal) {
switch (signal) {
case 'SIGINT':
case 'SIGTERM':
console.log(chalk.green(`[${worker.id}] exited by signal: ${signal}`));
break;
default:
console.error(chalk.red(`[${worker.id}] killed by signal: ${signal}`));
cluster.fork(); cluster.fork();
break;
}
} else if (code !== 0) {
console.error(chalk.red(`[${worker.id}] exited with error code: ${code}`));
} else {
console.log(chalk.green(`[${worker.id}] exited normally`));
}
}); });
}
// Display detail of unhandled promise rejection // Display detail of unhandled promise rejection
if (!envOption.quiet) { if (!envOption.quiet) {

View File

@ -254,7 +254,7 @@ export class ServerService implements OnApplicationShutdown {
@bindThis @bindThis
public async dispose(): Promise<void> { public async dispose(): Promise<void> {
await this.streamingApiServerService.detach(); this.streamingApiServerService.detach();
await this.#fastify.close(); await this.#fastify.close();
} }

View File

@ -173,13 +173,12 @@ export class StreamingApiServerService {
} }
@bindThis @bindThis
public detach(): Promise<void> { public detach(): void {
if (this.#cleanConnectionsIntervalId) { if (this.#cleanConnectionsIntervalId) {
clearInterval(this.#cleanConnectionsIntervalId); clearInterval(this.#cleanConnectionsIntervalId);
this.#cleanConnectionsIntervalId = null; this.#cleanConnectionsIntervalId = null;
} }
return new Promise((resolve) => { this.#wss.close();
this.#wss.close(() => resolve()); this.#wss.clients.forEach(client => client.terminate());
});
} }
} }