Conversation
Make ClaudePool.force_kill() async so it can call instance.shutdown() instead of raw instance.force_kill(). shutdown() does full cleanup: SIGTERM, SIGKILL escalation, stderr task cancellation, process state clearing, and process group kill. Without this, force_kill left orphaned stderr tasks, zombie processes, and unkilled process groups. Wraps shutdown() in a 5-second timeout with raw force_kill() fallback so it never blocks callers indefinitely. Fixes #133
Review by KaiPR Review:
|
…nalty The timeout test was waiting the full 5 seconds for wait_for to fire. Extract the timeout as a module constant and patch it to 0.01s in the test.
Review by KaiReview:
|
Summary
ClaudePool.force_kill()async so it can callinstance.shutdown()for full process cleanupforce_kill()calledinstance.force_kill()which only sends raw SIGKILL with no cleanup: stderr task leaked, process state not cleared, process group not killedshutdown()does SIGTERM -> SIGKILL escalation -> cancel stderr -> clear state -> killpgasyncio.wait_for(timeout=5)with rawforce_kill()fallback so it never blocks indefinitelyChanges
src/kai/pool.pyforce_kill()now async, callsshutdown()with timeout fallbacksrc/kai/bot.py/stop) updated toawaittests/test_pool.pytests/test_bot.py_make_mock_claudepool mock usesAsyncMockforforce_killTest plan
test_force_kill_specific_user- verifies shutdown called on target, not on other userstest_force_kill_no_instance- no-op for unknown usertest_force_kill_shutdown_timeout_falls_back- when shutdown hangs, falls back to raw SIGKILLtest_sets_stop_event_and_kills,test_timeout_kills_claude) pass with async mockmake checkcleanFixes #133