Skip to content

Commit c7c2221

Browse files
committed
fix(tests): reap orphaned descendants after each test
conftest sets PR_SET_CHILD_SUBREAPER so daemonized descendants reparent to the pytest session, but the framework only waitpid()s the firecracker PID. Other helpers (screen, ssh, vhost-user backends, socat-forked cat) linger as zombies, and their queued signals stay charged against the RLIMIT_SIGPENDING pool until reaped, which can cause later signal sends to be dropped. Add a per-test reap loop that drains exited descendants on teardown, ordered after the microVM is killed via a microvm_factory dependency. Signed-off-by: Riccardo Mancini <mancio@amazon.com>
1 parent 4888aac commit c7c2221

1 file changed

Lines changed: 34 additions & 2 deletions

File tree

tests/conftest.py

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,23 @@
6060
raise OSError(ctypes.get_errno(), "prctl(PR_SET_CHILD_SUBREAPER) failed")
6161

6262

63+
def reap_orphaned_children():
64+
"""Reap descendants that have reparented to this subreaper session.
65+
66+
Non-blocking; safe to call repeatedly. Returns the number reaped.
67+
"""
68+
reaped = 0
69+
while True:
70+
try:
71+
pid, _status = os.waitpid(-1, os.WNOHANG)
72+
except ChildProcessError:
73+
break
74+
if pid == 0:
75+
break
76+
reaped += 1
77+
return reaped
78+
79+
6380
METRICS = get_metrics_logger()
6481
PHASE_REPORT_KEY = pytest.StashKey[dict[str, pytest.CollectReport]]()
6582

@@ -126,6 +143,17 @@ def record_props(request, record_property):
126143
record_property("description", function_docstring)
127144

128145

146+
@pytest.fixture(scope="function")
147+
def reap_orphans():
148+
"""Reap orphaned descendants after each test.
149+
150+
Teardown runs after the microVM is killed because `microvm_factory`
151+
depends on this fixture (fixtures finalize in reverse setup order).
152+
"""
153+
yield
154+
reap_orphaned_children()
155+
156+
129157
def pytest_runtest_logreport(report):
130158
"""Send general test metrics to CloudWatch"""
131159

@@ -374,8 +402,12 @@ def get(self, _netns_id):
374402

375403

376404
@pytest.fixture()
377-
def microvm_factory(request, record_property, results_dir, netns_factory):
378-
"""Fixture to create microvms simply."""
405+
def microvm_factory(request, record_property, results_dir, netns_factory, reap_orphans):
406+
"""Fixture to create microvms simply.
407+
408+
Depends on `reap_orphans` for teardown ordering (reaping runs after
409+
the VMs are killed).
410+
"""
379411

380412
binary_dir = request.config.getoption("--binary-dir") or DEFAULT_BINARY_DIR
381413
if isinstance(binary_dir, str):

0 commit comments

Comments
 (0)