1+ /**
2+ * Spawned detached by the API restart endpoint.
3+ * Kills the old bot process, waits for cleanup, then starts a new detached instance.
4+ */
15const { spawn } = require ( "child_process" ) ;
26const fs = require ( "fs" ) ;
37const path = require ( "path" ) ;
48
5- const PID_FILE = path . join ( process . cwd ( ) , "data" , "bot.pid" ) ;
6- const START_SCRIPT = path . join ( process . cwd ( ) , "index.js" ) ;
9+ const ROOT = process . cwd ( ) ;
10+ const PID_FILE = path . join ( ROOT , "data" , "bot.pid" ) ;
11+ const LOG_FILE = path . join ( ROOT , "logs" , "bot.log" ) ;
12+ const ENTRY = path . join ( ROOT , "index.js" ) ;
713
814function sleep ( ms ) {
915 return new Promise ( ( resolve ) => setTimeout ( resolve , ms ) ) ;
1016}
1117
18+ function log ( msg ) {
19+ const line = `[${ new Date ( ) . toISOString ( ) } ] [restart-bot] ${ msg } \n` ;
20+ process . stderr . write ( line ) ;
21+ try {
22+ fs . appendFileSync ( LOG_FILE , line ) ;
23+ } catch ( _ ) { /* best-effort */ }
24+ }
25+
1226async function main ( ) {
13- console . log ( "[ Restart] Bot restart initiated.. ." ) ;
27+ log ( "Restart triggered ." ) ;
1428
29+ // Stop old process
1530 if ( fs . existsSync ( PID_FILE ) ) {
16- try {
17- const oldPid = parseInt ( fs . readFileSync ( PID_FILE , "utf8" ) . trim ( ) , 10 ) ;
18- if ( oldPid && ! isNaN ( oldPid ) ) {
19- console . log ( `[Restart] Attempting to stop old process (PID: ${ oldPid } )` ) ;
20- try {
21- process . kill ( oldPid , "SIGTERM" ) ;
22- } catch ( e ) {
23- console . log ( "[Restart] Old process already gone" ) ;
24- }
31+ const raw = fs . readFileSync ( PID_FILE , "utf8" ) . trim ( ) ;
32+ const oldPid = parseInt ( raw , 10 ) ;
33+ if ( oldPid && ! Number . isNaN ( oldPid ) ) {
34+ log ( `Sending SIGTERM to old process (PID ${ oldPid } )` ) ;
35+ try {
36+ process . kill ( oldPid , "SIGTERM" ) ;
37+ } catch ( _ ) {
38+ log ( "Old process already gone." ) ;
2539 }
26- } catch ( e ) {
27- console . log ( "[Restart] Could not read old PID file" ) ;
2840 }
2941 }
3042
31- console . log ( "[Restart] Waiting for cleanup..." ) ;
43+ log ( "Waiting for cleanup..." ) ;
3244 await sleep ( 2000 ) ;
3345
34- const env = { ...process . env } ;
35- console . log ( `[Restart] Starting bot from ${ START_SCRIPT } ...` ) ;
46+ // Start new detached process, output to log file
47+ fs . mkdirSync ( path . join ( ROOT , "logs" ) , { recursive : true } ) ;
48+ fs . mkdirSync ( path . join ( ROOT , "data" ) , { recursive : true } ) ;
3649
37- const child = spawn ( "node" , [ START_SCRIPT ] , {
38- env,
39- cwd : process . cwd ( ) ,
40- stdio : "inherit" ,
41- detached : false ,
42- } ) ;
50+ fs . appendFileSync ( LOG_FILE , `\n[${ new Date ( ) . toISOString ( ) } ] ──── Restarted by API ────\n` ) ;
4351
44- fs . writeFileSync ( PID_FILE , String ( child . pid ) ) ;
52+ const logFd = fs . openSync ( LOG_FILE , "a" ) ;
53+ const child = spawn ( "node" , [ ENTRY ] , {
54+ cwd : ROOT ,
55+ env : process . env ,
56+ detached : true ,
57+ stdio : [ "ignore" , logFd , logFd ] ,
58+ } ) ;
4559
46- console . log ( `[Restart] New bot started with PID: ${ child . pid } ` ) ;
60+ child . unref ( ) ;
61+ fs . closeSync ( logFd ) ;
4762
48- child . on ( "exit" , ( code ) => {
49- console . log ( `[Restart] Bot process exited with code ${ code } ` ) ;
50- process . exit ( code ) ;
51- } ) ;
63+ fs . writeFileSync ( PID_FILE , String ( child . pid ) ) ;
64+ log ( `New bot started (PID ${ child . pid } )` ) ;
5265}
5366
5467main ( ) . catch ( ( err ) => {
55- console . error ( "[Restart] Failed to restart:" , err ) ;
68+ log ( `Fatal: ${ err . message } ` ) ;
5669 process . exit ( 1 ) ;
57- } ) ;
70+ } ) ;
0 commit comments