* feat: call upstream stop API when aborting a run
- Modified handleAbort to call POST /v1/runs/{run_id}/stop endpoint
- Use profile-specific upstream URL and API key from gatewayManager
- Add 5-second timeout with error handling and logging
- Keep local abortController.abort() for EventSource cleanup
- Change handleAbort to async method and update call site
This ensures the upstream Hermes gateway is properly notified
when a user aborts a run, allowing graceful termination.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: close ChatRunSocket connections on shutdown to prevent hanging
- Add close() method to ChatRunSocket to abort all active runs
and clear session state
- Pass chatRunServer to bindShutdown and close it before
groupChatServer during shutdown
- This prevents EventSource connections and abort controllers
from keeping the process alive during nodemon restart
Fixes the "still waiting for sub-process to finish" issue.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Handle chat run abort lifecycle
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
45 lines
1.1 KiB
TypeScript
45 lines
1.1 KiB
TypeScript
import { logger } from './logger'
|
|
|
|
export function bindShutdown(server: any, groupChatServer?: any, chatRunServer?: any): void {
|
|
let isShuttingDown = false
|
|
|
|
const shutdown = async (signal: string) => {
|
|
if (isShuttingDown) return
|
|
isShuttingDown = true
|
|
|
|
logger.info('Shutting down (%s)...', signal)
|
|
|
|
try {
|
|
// Close ChatRunSocket first to abort all active runs and close EventSource connections
|
|
if (chatRunServer) {
|
|
chatRunServer.close()
|
|
logger.info('ChatRunSocket closed')
|
|
}
|
|
|
|
// Disconnect Socket.IO before HTTP server to prevent hanging
|
|
if (groupChatServer) {
|
|
groupChatServer.agentClients.disconnectAll()
|
|
groupChatServer.getIO().close()
|
|
logger.info('Socket.IO closed')
|
|
}
|
|
|
|
if (server) {
|
|
await new Promise<void>((resolve) => {
|
|
server.close(() => {
|
|
logger.info('HTTP server closed')
|
|
resolve()
|
|
})
|
|
})
|
|
}
|
|
} catch (err) {
|
|
logger.error(err, 'Shutdown error')
|
|
}
|
|
|
|
process.exit(0)
|
|
}
|
|
|
|
process.once('SIGUSR2', shutdown)
|
|
process.on('SIGINT', shutdown)
|
|
process.on('SIGTERM', shutdown)
|
|
}
|