From 3e0dba7172fb83f8761b99843e67f2441852aa3c Mon Sep 17 00:00:00 2001 From: "QCQCQC@Debian" Date: Wed, 10 Dec 2025 10:55:41 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BF=AE=E5=A4=8DstopRoutine=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E6=89=A7=E8=A1=8C=EF=BC=8C=E5=B9=B6=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/server/start.js | 65 ++++++++++++++++++++++++--------- src/server/start.ts | 68 +++++++++++++++++++++++++---------- template/src/routines/stop.ts | 26 ++++++++++++++ 3 files changed, 124 insertions(+), 35 deletions(-) create mode 100644 template/src/routines/stop.ts diff --git a/lib/server/start.js b/lib/server/start.js index a4d5e99..555c73c 100644 --- a/lib/server/start.js +++ b/lib/server/start.js @@ -402,33 +402,64 @@ async function startup(path, connector, omitWatchers, omitTimers, routine) { if (!omitTimers) { appLoader.startTimers(); } + let isShutingdown = false; const shutdown = async () => { - await httpServer.close(); - await koa.removeAllListeners(); - await appLoader.execStopRoutines(); - await appLoader.unmount(); - (0, polyfill_1.removePolyfill)("startup"); + if (isShutingdown) { + return; + } + isShutingdown = true; + console.log('服务器正在关闭中...'); + try { + await httpServer.close(); + await koa.removeAllListeners(); + await appLoader.execStopRoutines(); + await appLoader.unmount(); + (0, polyfill_1.removePolyfill)("startup"); + } + catch (err) { + console.error('关闭服务器时出错:', err); + } + }; + // 处理优雅关闭的统一入口 + let shutdownStarted = false; + const handleShutdown = async (signal) => { + // 防止重复处理 + if (shutdownStarted) { + console.warn('关闭流程已启动,忽略此信号'); + return; + } + shutdownStarted = true; + console.log(`\n收到 ${signal} 信号,准备关闭服务器...`); + // 移除所有信号处理器,防止重复触发 + process.removeAllListeners('SIGINT'); + process.removeAllListeners('SIGTERM'); + process.removeAllListeners('SIGQUIT'); + process.removeAllListeners('SIGHUP'); + try { + await shutdown(); + process.exit(0); + } + catch (err) { + console.error('关闭过程出错:', err); + process.exit(1); + } }; // 监听终止信号进行优雅关闭 // SIGINT - Ctrl+C 发送的中断信号 - process.on('SIGINT', async () => { - await shutdown(); - process.exit(0); + process.on('SIGINT', () => { + handleShutdown('SIGINT'); }); // SIGTERM - 系统/容器管理器发送的终止信号(Docker、K8s、PM2等) - process.on('SIGTERM', async () => { - await shutdown(); - process.exit(0); + process.on('SIGTERM', () => { + handleShutdown('SIGTERM'); }); // SIGQUIT - Ctrl+\ 发送的退出信号 - process.on('SIGQUIT', async () => { - await shutdown(); - process.exit(0); + process.on('SIGQUIT', () => { + handleShutdown('SIGQUIT'); }); // SIGHUP - 终端关闭时发送(可选) - process.on('SIGHUP', async () => { - await shutdown(); - process.exit(0); + process.on('SIGHUP', () => { + handleShutdown('SIGHUP'); }); return shutdown; } diff --git a/src/server/start.ts b/src/server/start.ts index 63bbc38..4cb3992 100644 --- a/src/server/start.ts +++ b/src/server/start.ts @@ -492,38 +492,70 @@ export async function startup { - await httpServer.close(); - await koa.removeAllListeners(); - await appLoader.execStopRoutines(); - await appLoader.unmount(); - - removePolyfill("startup"); + if (isShutingdown) { + return; + } + isShutingdown = true; + console.log('服务器正在关闭中...'); + try { + await httpServer.close(); + await koa.removeAllListeners(); + await appLoader.execStopRoutines(); + await appLoader.unmount(); + removePolyfill("startup"); + } catch (err) { + console.error('关闭服务器时出错:', err); + } } + // 处理优雅关闭的统一入口 + let shutdownStarted = false; + const handleShutdown = async (signal: string) => { + // 防止重复处理 + if (shutdownStarted) { + console.warn('关闭流程已启动,忽略此信号'); + return; + } + shutdownStarted = true; + + console.log(`\n收到 ${signal} 信号,准备关闭服务器...`); + + // 移除所有信号处理器,防止重复触发 + process.removeAllListeners('SIGINT'); + process.removeAllListeners('SIGTERM'); + process.removeAllListeners('SIGQUIT'); + process.removeAllListeners('SIGHUP'); + + try { + await shutdown(); + process.exit(0); + } catch (err) { + console.error('关闭过程出错:', err); + process.exit(1); + } + }; + // 监听终止信号进行优雅关闭 // SIGINT - Ctrl+C 发送的中断信号 - process.on('SIGINT', async () => { - await shutdown(); - process.exit(0); + process.on('SIGINT', () => { + handleShutdown('SIGINT'); }); // SIGTERM - 系统/容器管理器发送的终止信号(Docker、K8s、PM2等) - process.on('SIGTERM', async () => { - await shutdown(); - process.exit(0); + process.on('SIGTERM', () => { + handleShutdown('SIGTERM'); }); // SIGQUIT - Ctrl+\ 发送的退出信号 - process.on('SIGQUIT', async () => { - await shutdown(); - process.exit(0); + process.on('SIGQUIT', () => { + handleShutdown('SIGQUIT'); }); // SIGHUP - 终端关闭时发送(可选) - process.on('SIGHUP', async () => { - await shutdown(); - process.exit(0); + process.on('SIGHUP', () => { + handleShutdown('SIGHUP'); }); return shutdown diff --git a/template/src/routines/stop.ts b/template/src/routines/stop.ts new file mode 100644 index 0000000..7e3ec01 --- /dev/null +++ b/template/src/routines/stop.ts @@ -0,0 +1,26 @@ +import { Routine } from 'oak-domain/lib/types/Timer'; +import { EntityDict } from '@oak-app-domain'; +import { BackendRuntimeContext } from '../context/BackendRuntimeContext'; + +// process.on('uncaughtException', (err) => { +// console.error(`Caught exception: ${err}`); +// // Optionally, you can exit the process or perform cleanup +// }); + +// process.on('unhandledRejection', (err) => { +// console.error(`Caught rejection: ${err}`); +// // Optionally, you can exit the process or perform cleanup +// }); + + +const stopRoutines: Array> = [ + { + name: '示例性routine_stop', + routine: async (context, env) => { + console.log('示例性routine执行,请在src/routine/stop.ts中关闭'); + return context.opResult; + }, + }, +]; + +export default stopRoutines;