diff --git a/bot_bottle/sidecar_init.py b/bot_bottle/sidecar_init.py index 8bfa984..2b303a6 100644 --- a/bot_bottle/sidecar_init.py +++ b/bot_bottle/sidecar_init.py @@ -245,7 +245,12 @@ class _Supervisor: except ProcessLookupError: pass - return all(p.poll() is not None for _, p in self.procs) + done = all(p.poll() is not None for _, p in self.procs) + if done: + for _, p in self.procs: + if p.stdout is not None: + p.stdout.close() + return done def exit_code(self) -> int: """Positive child failures win; otherwise report success. @@ -335,6 +340,8 @@ class _Supervisor: except ProcessLookupError: pass p.wait() + if p.stdout is not None: + p.stdout.close() self._logged_dead.discard(daemon_name) new_proc = _spawn(spec) self.procs[idx] = (spec, new_proc) diff --git a/tests/unit/test_sidecar_init.py b/tests/unit/test_sidecar_init.py index 88f0b9b..1256af0 100644 --- a/tests/unit/test_sidecar_init.py +++ b/tests/unit/test_sidecar_init.py @@ -14,6 +14,7 @@ import subprocess import sys import time import unittest +import warnings from pathlib import Path from unittest.mock import patch @@ -135,6 +136,10 @@ class TestSupervisor(unittest.TestCase): We don't go through `main()` because main installs signal handlers process-wide, which collides with the test runner.""" + def setUp(self): + warnings.simplefilter("error", ResourceWarning) + self.addCleanup(warnings.resetwarnings) + def _drive(self, sup: _Supervisor, max_wait_s: float = 6.0) -> int: deadline = time.monotonic() + max_wait_s while not sup.tick():