Skip to content

Commit

Permalink
PYTHON-4147: Silence noisy thread.start() RuntimeError at shutdown (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
Jibola committed Feb 5, 2024
1 parent da2bf9d commit 0f7e1b0
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 1 deletion.
3 changes: 3 additions & 0 deletions doc/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ PyMongo 4.7 brings a number of improvements including:

.. _orjson: https://github.com/ijl/orjson

- Fixed a bug appearing in Python 3.12 where "RuntimeError: can't create new thread at interpreter shutdown"
could be written to stderr when a MongoClient's thread starts as the python interpreter is shutting down.

Changes in Version 4.6.1
------------------------

Expand Down
11 changes: 10 additions & 1 deletion pymongo/periodic_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

from __future__ import annotations

import sys
import threading
import time
import weakref
Expand Down Expand Up @@ -91,7 +92,15 @@ def open(self) -> None:
thread.daemon = True
self._thread = weakref.proxy(thread)
_register_executor(self)
thread.start()
# Mitigation to RuntimeError firing when thread starts on shutdown
# https://github.com/python/cpython/issues/114570
try:
thread.start()
except RuntimeError as e:
if "interpreter shutdown" in str(e) or sys.is_finalizing():
self._thread = None
return
raise

def close(self, dummy: Any = None) -> None:
"""Stop. To restart, call open().
Expand Down
12 changes: 12 additions & 0 deletions test/test_monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from __future__ import annotations

import gc
import subprocess
import sys
from functools import partial

Expand Down Expand Up @@ -79,6 +80,17 @@ def test_cleanup_executors_on_client_close(self):
for executor in executors:
wait_until(lambda: executor._stopped, f"closed executor: {executor._name}", timeout=5)

def test_no_thread_start_runtime_err_on_shutdown(self):
"""Test we silence noisy runtime errors fired when the MongoClient spawns a new thread
on process shutdown."""
command = [sys.executable, "-c", "'from pymongo import MongoClient; c = MongoClient()'"]
completed_process: subprocess.CompletedProcess = subprocess.run(
" ".join(command), shell=True, capture_output=True
)

self.assertFalse(completed_process.stderr)
self.assertFalse(completed_process.stdout)


if __name__ == "__main__":
unittest.main()

0 comments on commit 0f7e1b0

Please sign in to comment.