: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
-----------
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():
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):
--- /dev/null
+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.