Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions ops/devlane/dispatch/tests/launch_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,18 @@ def sha256_file(path) -> str:


def pid_is_alive(pid: int) -> bool:
# A group SIGKILL can leave a descendant as a zombie until the host's
# init process reaps it. ``kill(pid, 0)`` still succeeds for zombies,
# even though they cannot execute and therefore are not survivors of the
# isolation boundary. Check procfs first so the process-group assertion
# measures live workers rather than the reaping behaviour of PID 1 (which
# is notably delayed in some CI containers).
stat = Path(f"/proc/{pid}/stat")
try:
if stat.read_text(encoding="utf-8").split()[2] == "Z":
return False
except (FileNotFoundError, IndexError, OSError):
pass
try:
os.kill(pid, 0)
except ProcessLookupError:
Expand Down
8 changes: 8 additions & 0 deletions ops/devlane/task/tests/test_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -1307,6 +1307,14 @@ def _orphan_maker(self):

@staticmethod
def _alive(pid):
# kill(0) also reports zombies as present. A killed orphan can stay
# zombied until PID 1 reaps it in a container, but it is no longer a
# runnable descendant and must not make this isolation check flaky.
try:
if Path(f"/proc/{pid}/stat").read_text().split()[2] == "Z":
return False
except (FileNotFoundError, IndexError, OSError):
pass
try:
os.kill(pid, 0)
return True
Expand Down
Loading