@@ -13,13 +13,27 @@ process.argv.includes(`--log-line`) && logHelper()
1313
1414const fs = require ( `fs` )
1515const path = require ( `path` )
16+ const util = require ( 'util' )
1617const { tool, business } = require ( `${ __dirname } /util/index.js` )
1718const lib = require ( `${ __dirname } /util/lib.js` )
1819const packageJson = require ( `${ __dirname } /package.json` )
1920const cli = tool . cli
2021const cliArg = cli . parseArgv ( )
2122const serverPath = path . normalize ( `${ __dirname } /server.js` ) // 转换为跨平台的路径
22- const { ProcessManager } = require ( `@wll8/process-manager` )
23+ const pm2 = require ( 'pm2' )
24+
25+ // 使用 util.promisify 封装 PM2 的回调方法
26+ const pm2Async = {
27+ connect : util . promisify ( pm2 . connect . bind ( pm2 ) ) ,
28+ start : util . promisify ( pm2 . start . bind ( pm2 ) ) ,
29+ restart : util . promisify ( pm2 . restart . bind ( pm2 ) ) ,
30+ stop : util . promisify ( pm2 . stop . bind ( pm2 ) ) ,
31+ delete : util . promisify ( pm2 . delete . bind ( pm2 ) ) ,
32+ list : util . promisify ( pm2 . list . bind ( pm2 ) ) ,
33+ sendDataToProcessId : util . promisify ( pm2 . sendDataToProcessId . bind ( pm2 ) ) ,
34+ launchBus : util . promisify ( pm2 . launchBus . bind ( pm2 ) ) ,
35+ disconnect : ( ) => pm2 . disconnect ( ) // 这个方法不需要 promisify
36+ }
2337
2438{ // 尽早的, 无依赖的修改 cwd, 避免其他读取到旧值
2539 const cwd = tool . cli . handlePathArg (
@@ -90,42 +104,109 @@ new Promise( async () => { // 检查更新
90104
91105new Promise ( async ( ) => { // 启动 server.js
92106 let log = ``
107+ let isShuttingDown = false
93108 const nodeArg = typeof ( cliArg [ `--node-options` ] ) === `string` ? cliArg [ `--node-options` ] : ``
94- const arr = [ nodeArg , serverPath , ...process . argv . slice ( 2 ) , `_base64=${ base64config } ` , `_share=${ sharePath } ` ] . filter ( item => item . trim ( ) !== `` )
95- const cp = new ProcessManager ( arr )
96- cp . on ( `stdout` , ( data ) => {
97- log = String ( data )
98- } )
99- cp . on ( `stderr` , ( data ) => {
100- log = String ( data )
101- } )
102- cp . on ( `message` , ( { action, data} = { } ) => {
103- if ( action === `reboot` ) {
104- cp . reboot ( 0 )
105- }
106- if ( action === `config` ) {
107- cp . autoReStart = data . guard
108- }
109- } )
110- cp . on ( `close` , ( ) => {
111- if ( log . match ( / k i l l P r o c e s s : / ) ) { // 保存错误日志
112- saveLog ( {
113- code : `` ,
114- logStr : log ,
115- logPath : shareConfig . _errLog ,
116- } )
117- }
118- } )
109+ const processName = `mockm-${ process . pid } `
110+
111+ // PM2 进程配置
112+ const pm2Config = {
113+ name : processName ,
114+ script : serverPath ,
115+ args : [ ...process . argv . slice ( 2 ) , `_base64=${ base64config } ` , `_share=${ sharePath } ` ] ,
116+ nodeArgs : nodeArg ? nodeArg . split ( ' ' ) . filter ( arg => arg . trim ( ) ) : [ ] ,
117+ cwd : process . cwd ( ) ,
118+ autorestart : false , // 手动控制重启
119+ watch : false , // 关闭 PM2 自带的文件监听,使用自定义监听
120+ max_memory_restart : '500M' ,
121+ merge_logs : true ,
122+ kill_timeout : 5000 ,
123+ namespace : process . env . PM2_NAMESPACE ,
124+ // 不指定日志文件,让 PM2 使用默认位置,然后我们通过流来转发
125+ silent : false
126+ }
119127
128+ // 监听进程消息和日志
129+ async function listenToProcessMessages ( ) {
130+ const pm2_bus = await pm2Async . launchBus ( )
131+
132+ // 监听日志输出
133+ pm2_bus . on ( 'log:out' , ( packet ) => {
134+ if ( packet . process . name === processName ) {
135+ process . stdout . write ( packet . data )
136+ log = String ( packet . data )
137+ }
138+ } )
139+
140+ pm2_bus . on ( 'log:err' , ( packet ) => {
141+ if ( packet . process . name === processName ) {
142+ process . stderr . write ( packet . data )
143+ log = String ( packet . data )
144+ }
145+ } )
146+
147+ pm2_bus . on ( 'process:msg' , ( packet ) => {
148+ if ( packet . process . name === processName ) {
149+ const { action, data = { } } = packet . data || { }
150+ if ( action === 'err-exit' ) {
151+ if ( pm2Config . autorestart ) {
152+ console . log ( `[${ processName } ] Auto restarting process...` )
153+ } else {
154+ killProcess ( )
155+ }
156+ }
157+ if ( action === 'reboot' ) {
158+ pm2Async . restart ( processName )
159+ }
160+
161+ if ( action === 'config' ) {
162+ pm2Config . autorestart = data . guard
163+ }
164+ }
165+ } )
166+ }
167+
168+ // 优雅关闭函数
120169 function killProcess ( ) {
121- cp . kill ( )
122- process . exit ( )
170+ isShuttingDown = true
171+ console . log ( `[${ processName } ] Shutting down...` )
172+ pm2Async . delete ( processName )
173+ . then ( ( ) => {
174+ pm2Async . disconnect ( )
175+ process . exit ( 0 )
176+ } )
177+ . catch ( err => {
178+ console . error ( 'Error during shutdown:' , err )
179+ pm2Async . disconnect ( )
180+ process . exit ( 1 )
181+ } )
123182 }
183+
184+ // 绑定进程信号
124185 process . on ( `SIGTERM` , killProcess )
125186 process . on ( `SIGINT` , killProcess )
126187 process . on ( `uncaughtException` , killProcess )
127188 process . on ( `unhandledRejection` , killProcess )
128189
190+ try {
191+
192+ // 启动 PM2 管理的进程
193+ await pm2Async . connect ( )
194+
195+ // 先清理可能存在的同名进程
196+ await pm2Async . delete ( processName ) . catch ( ( ) => { } ) // 忽略错误,因为进程可能不存在
197+
198+ // 启动新进程
199+ await pm2Async . start ( pm2Config )
200+
201+ // 监听进程消息
202+ listenToProcessMessages ( )
203+
204+ } catch ( err ) {
205+ console . error ( 'Failed to start process:' , err )
206+ pm2Async . disconnect ( )
207+ process . exit ( 1 )
208+ }
209+
129210 const {
130211 showLocalInfo,
131212 remoteServer,
0 commit comments