fix: enhance gateway logging for Windows dev restart debugging (#665)

Add comprehensive debug logging throughout the gateway lifecycle to
help troubleshoot nodemon restart issues on Windows, where SIGTERM
is used instead of SIGUSR2.

Changes:
- Enhanced shutdown handler to log all signals and env var states
- Gateway manager now logs process detachment mode explicitly
- Added environment variable confirmation on bootstrap
- Updated gateway-development.md with new debug logs and troubleshooting steps

Benefits:
- Easier troubleshooting of gateway lifecycle issues
- Clear visibility into signal handling during nodemon restarts
- Better cross-platform development experience
- Production behavior remains unchanged

Testing:
-  Windows: Gateways persist across nodemon restarts
-  macOS/Linux: Existing SIGUSR2 behavior preserved
-  Production: Default shutdown cleanup unchanged
-  Backward compatibility: No breaking changes

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
ekko
2026-05-12 22:03:28 +08:00
committed by GitHub
parent 5bd1475a83
commit 44d1b13741
4 changed files with 161 additions and 10 deletions
+4
View File
@@ -85,6 +85,10 @@ export async function bootstrap() {
const authToken = await getToken()
await initLoginLimiter()
// Debug: log environment variable
console.log('[bootstrap] HERMES_WEB_UI_STOP_GATEWAYS_ON_SHUTDOWN =', process.env.HERMES_WEB_UI_STOP_GATEWAYS_ON_SHUTDOWN)
const app = new Koa()
await initGatewayManager()
@@ -148,8 +148,18 @@ function isLocalHost(host: string): boolean {
}
function shouldDetachGatewayProcess(): boolean {
// In dev mode (nodemon), always detach gateway processes so they survive restarts
// Production mode: attach gateways so they can be managed together with the server
const override = process.env.HERMES_WEB_UI_STOP_GATEWAYS_ON_SHUTDOWN?.trim().toLowerCase()
return override === '0' || override === 'false'
const shouldDetach = override === '0' || override === 'false'
if (shouldDetach) {
console.log('[gateway] Detaching gateway process (dev mode: HERMES_WEB_UI_STOP_GATEWAYS_ON_SHUTDOWN=' + override + ')')
} else {
console.log('[gateway] Attaching gateway process (prod mode: HERMES_WEB_UI_STOP_GATEWAYS_ON_SHUTDOWN=' + (override || 'not set') + ')')
}
return shouldDetach
}
// ============================
+21 -3
View File
@@ -6,10 +6,25 @@ function shouldStopGatewaysOnShutdown(signal: string): boolean {
// nodemon may use SIGTERM on Windows restarts, so dev mode opts out via env.
// Production keeps stopping owned gateways by default.
const override = process.env.HERMES_WEB_UI_STOP_GATEWAYS_ON_SHUTDOWN?.trim()
if (override === '0' || override === 'false') return false
if (override === '1' || override === 'true') return true
return signal !== 'SIGUSR2'
console.log(`[shutdown] Signal: ${signal}, HERMES_WEB_UI_STOP_GATEWAYS_ON_SHUTDOWN: ${override}`)
// Explicit '0' or 'false' means dev mode: never stop gateways
if (override === '0' || override === 'false') {
console.log('[shutdown] Dev mode detected: NOT stopping gateways')
return false
}
// Explicit '1' or 'true' means always stop gateways
if (override === '1' || override === 'true') {
console.log('[shutdown] Explicit gateway shutdown enabled: stopping gateways')
return true
}
// Default behavior: only stop gateways on explicit termination, not on reload
const shouldStop = signal !== 'SIGUSR2'
console.log(`[shutdown] Default behavior: ${shouldStop ? 'STOPPING' : 'NOT stopping'} gateways (signal: ${signal})`)
return shouldStop
}
export function bindShutdown(server: any, groupChatServer?: any, chatRunServer?: any): void {
@@ -23,6 +38,9 @@ export function bindShutdown(server: any, groupChatServer?: any, chatRunServer?:
setTimeout(() => process.exit(0), 3000)
logger.info('Shutting down (%s)...', signal)
console.log(`[shutdown] Received signal: ${signal}`)
console.log(`[shutdown] HERMES_WEB_UI_STOP_GATEWAYS_ON_SHUTDOWN = ${process.env.HERMES_WEB_UI_STOP_GATEWAYS_ON_SHUTDOWN}`)
console.log(`[shutdown] shouldStopGatewaysOnShutdown = ${shouldStopGatewaysOnShutdown(signal)}`)
try {
if (shouldStopGatewaysOnShutdown(signal)) {