fix(process): label background completion causes (#46659)

Track why a background process finished and include that source in notify-on-complete messages so SIGTERM from process.kill, kill_all, backend loss, and ordinary exits are distinguishable.
This commit is contained in:
Teknium
2026-06-15 07:08:24 -07:00
committed by GitHub
parent 733472952a
commit be7c919bf9
5 changed files with 128 additions and 19 deletions
+32 -1
View File
@@ -12,7 +12,7 @@ import json
import os
import time
import pytest
from unittest.mock import patch
from unittest.mock import MagicMock, patch
from tools.process_registry import (
ProcessRegistry,
@@ -99,6 +99,8 @@ class TestCompletionQueue:
assert completion["session_id"] == s.id
assert completion["command"] == "echo hello"
assert completion["exit_code"] == 0
assert completion["completion_reason"] == "exited"
assert completion["termination_source"] == ""
assert "build succeeded" in completion["output"]
def test_move_to_finished_nonzero_exit(self, registry):
@@ -138,6 +140,35 @@ class TestCompletionQueue:
completion = registry.completion_queue.get_nowait()
assert completion["exit_code"] == -15 # from the first (kill) call
def test_kill_process_sets_completion_reason_and_source(self, registry):
s = _make_session(notify_on_complete=True, output="stopping")
s.process = MagicMock()
s.process.pid = 4242
registry._running[s.id] = s
class FakeProcess:
def __init__(self, pid):
self.pid = pid
def children(self, recursive=False):
return []
def terminate(self):
pass
import psutil as _psutil
with patch.object(_psutil, "Process", side_effect=lambda pid: FakeProcess(pid)), \
patch.object(registry, "_write_checkpoint"):
result = registry.kill_process(s.id)
assert result["status"] == "killed"
assert result["completion_reason"] == "killed"
assert result["termination_source"] == "process.kill"
completion = registry.completion_queue.get_nowait()
assert completion["completion_reason"] == "killed"
assert completion["termination_source"] == "process.kill"
def test_output_truncated_to_2000(self, registry):
"""Long output is truncated to last 2000 chars."""
long_output = "x" * 5000