()
| 276 | } |
| 277 | |
| 278 | export async function stopRunner() { |
| 279 | try { |
| 280 | const state = await readRunnerState(); |
| 281 | if (!state) { |
| 282 | logger.debug('No runner state found'); |
| 283 | return; |
| 284 | } |
| 285 | |
| 286 | logger.debug(`Stopping runner with PID ${state.pid}`); |
| 287 | |
| 288 | // Try HTTP graceful stop |
| 289 | try { |
| 290 | await stopRunnerHttp(); |
| 291 | |
| 292 | // Wait for runner to die |
| 293 | await waitForProcessDeath(state.pid, 2000); |
| 294 | logger.debug('Runner stopped gracefully via HTTP'); |
| 295 | return; |
| 296 | } catch (error) { |
| 297 | logger.debug('HTTP stop failed, will force kill', error); |
| 298 | } |
| 299 | |
| 300 | // Force kill |
| 301 | const killed = await killProcess(state.pid, true); |
| 302 | if (killed) { |
| 303 | logger.debug('Force killed runner'); |
| 304 | } else { |
| 305 | logger.debug('Runner already dead or could not be killed'); |
| 306 | } |
| 307 | } catch (error) { |
| 308 | logger.debug('Error stopping runner', error); |
| 309 | } |
| 310 | } |
| 311 | |
| 312 | async function waitForProcessDeath(pid: number, timeout: number): Promise<void> { |
| 313 | const start = Date.now(); |
no test coverage detected