https://github.com/python/cpython/commit/9e7340cd3b5531784291088b504882cfb4d4c78c
commit: 9e7340cd3b5531784291088b504882cfb4d4c78c
branch: main
author: J Berg <[email protected]>
committer: gpshead <[email protected]>
date: 2025-11-11T22:09:58Z
summary:
gh-139462: Make the ProcessPoolExecutor BrokenProcessPool exception report
which child process terminated (GH-139486)
Report which process terminated as cause of BPE
files:
A Misc/NEWS.d/next/Library/2025-10-02-22-29-00.gh-issue-139462.VZXUHe.rst
M Doc/whatsnew/3.15.rst
M Lib/concurrent/futures/process.py
M Lib/test/test_concurrent_futures/test_process_pool.py
diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst
index ecab0d03e105e6..c543b6e6c2a779 100644
--- a/Doc/whatsnew/3.15.rst
+++ b/Doc/whatsnew/3.15.rst
@@ -369,6 +369,16 @@ collections.abc
:mod:`!collections.abc` module.
+concurrent.futures
+------------------
+
+* Improved error reporting when a child process in a
+ :class:`concurrent.futures.ProcessPoolExecutor` terminates abruptly.
+ The resulting traceback will now tell you the PID and exit code of the
+ terminated process.
+ (Contributed by Jonathan Berg in :gh:`139486`.)
+
+
dataclasses
-----------
diff --git a/Lib/concurrent/futures/process.py
b/Lib/concurrent/futures/process.py
index a14650bf5fa47c..a42afa68efcb14 100644
--- a/Lib/concurrent/futures/process.py
+++ b/Lib/concurrent/futures/process.py
@@ -474,9 +474,23 @@ def _terminate_broken(self, cause):
bpe = BrokenProcessPool("A process in the process pool was "
"terminated abruptly while the future was "
"running or pending.")
+ cause_str = None
if cause is not None:
- bpe.__cause__ = _RemoteTraceback(
- f"\n'''\n{''.join(cause)}'''")
+ cause_str = ''.join(cause)
+ else:
+ # No cause known, so report any processes that have
+ # terminated with nonzero exit codes, e.g. from a
+ # segfault. Multiple may terminate simultaneously,
+ # so include all of them in the traceback.
+ errors = []
+ for p in self.processes.values():
+ if p.exitcode is not None and p.exitcode != 0:
+ errors.append(f"Process {p.pid} terminated abruptly "
+ f"with exit code {p.exitcode}")
+ if errors:
+ cause_str = "\n".join(errors)
+ if cause_str:
+ bpe.__cause__ = _RemoteTraceback(f"\n'''\n{cause_str}'''")
# Mark pending tasks as failed.
for work_id, work_item in self.pending_work_items.items():
diff --git a/Lib/test/test_concurrent_futures/test_process_pool.py
b/Lib/test/test_concurrent_futures/test_process_pool.py
index 9685f980119a0e..731419a48bd128 100644
--- a/Lib/test/test_concurrent_futures/test_process_pool.py
+++ b/Lib/test/test_concurrent_futures/test_process_pool.py
@@ -106,6 +106,21 @@ def test_traceback(self):
self.assertIn('raise RuntimeError(123) # some comment',
f1.getvalue())
+ def test_traceback_when_child_process_terminates_abruptly(self):
+ # gh-139462 enhancement - BrokenProcessPool exceptions
+ # should describe which process terminated.
+ exit_code = 99
+ with self.executor_type(max_workers=1) as executor:
+ future = executor.submit(os._exit, exit_code)
+ with self.assertRaises(BrokenProcessPool) as bpe:
+ future.result()
+
+ cause = bpe.exception.__cause__
+ self.assertIsInstance(cause, futures.process._RemoteTraceback)
+ self.assertIn(
+ f"terminated abruptly with exit code {exit_code}", cause.tb
+ )
+
@warnings_helper.ignore_fork_in_thread_deprecation_warnings()
@hashlib_helper.requires_hashdigest('md5')
def test_ressources_gced_in_workers(self):
diff --git
a/Misc/NEWS.d/next/Library/2025-10-02-22-29-00.gh-issue-139462.VZXUHe.rst
b/Misc/NEWS.d/next/Library/2025-10-02-22-29-00.gh-issue-139462.VZXUHe.rst
new file mode 100644
index 00000000000000..390a6124386151
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-10-02-22-29-00.gh-issue-139462.VZXUHe.rst
@@ -0,0 +1,3 @@
+When a child process in a :class:`concurrent.futures.ProcessPoolExecutor`
+terminates abruptly, the resulting traceback will now tell you the PID
+and exit code of the terminated process. Contributed by Jonathan Berg.
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]