Skip to content

PYTHON-5418 Support subinterpreters and InterpreterPoolExecutor - #31

Closed
blink1073 wants to merge 12 commits into
mainfrom
PYTHON-5418
Closed

blink1073 wants to merge 12 commits into
mainfrom
PYTHON-5418

Conversation

@blink1073

@blink1073 blink1073 commented Sep 21, 2026 •

Copy link
Copy Markdown
Owner

PYTHON-5418

Changes in this PR

  • PeriodicExecutor starts non-daemon threads in subinterpreters, where daemon threads are disallowed. The monitor shutdown handler is registered with threading._register_atexit (only in those interpreters) so executors are stopped and joined at interpreter teardown; main-interpreter shutdown ordering is unchanged.
  • Added tests for PeriodicExecutor in a subinterpreter and a dedicated test_subinterpreters.py‎ covering direct subinterpeter and InterpreterPoolExecutor usage with sync and aync clients.
  • Note: an interpreter may block on teardown until in-flight monitor work completes.
  • Almost all of the changes are new tests.

Test Plan

  • The new subinterpreter tests pass on Python 3.14 and 3.15.
  • With the shutdown changes reverted, test_subinterpreters fails, demonstrating regression coverage.

Checklist

Checklist for Author

  • Did you update the changelog (if necessary)?
  • Is there test coverage?
  • Is any followup work tracked in a JIRA ticket? If so, add link(s).

Checklist for Reviewer

  • Does the title of the PR reference a JIRA Ticket?
  • Do you fully understand the implementation? (Would you be comfortable explaining how this code works to someone else?)
  • Is all relevant documentation (README or docstring) updated?

PeriodicExecutor now falls back to a non-daemon thread when daemon threads are disallowed (subinterpreters). The monitor shutdown handler is also registered with threading._register_atexit so executors are stopped and joined before interpreter teardown.

Adds regression tests for PeriodicExecutor in a real subinterpreter and for concurrent MongoClients across subinterpreters (Python 3.14+).
Runs live MongoClients inside interpreters managed by the standard
InterpreterPoolExecutor, mirroring the existing multi-threaded checks.
The pool's interpreters do not allow daemon threads, so this exercises
the non-daemon monitor thread fallback and its shutdown handling.
The worker interpreters may not have the repo root on sys.path (the
stdlib test package shadows the repo's), so the pickled worker function
failed to unpickle.  Submit the builtin exec with a code string that
inserts the main interpreter's sys.path before importing pymongo.
Runs live AsyncMongoClients inside interpreters managed by
InterpreterPoolExecutor. The async client runs its background tasks on
the interpreter's own event loop rather than in threads, covering the
other shutdown path.
Invert the is_running guard in test_subinterpreters: closing an idle
interpreter runs threading._shutdown, which stops and joins pymongo's
monitor threads, so the successful path must close them. Note in the
changelog that both clients are covered by the subinterpreter tests.
Only register the monitor shutdown handler with
threading._register_atexit when the interpreter disallows daemon
threads, preserving normal main interpreter shutdown ordering.
Comment thread doc/changelog.rst Outdated
Comment thread pymongo/asynchronous/monitor.py Outdated
Comment thread pymongo/periodic_executor.py Outdated
Comment thread test/asynchronous/test_periodic_executor.py Outdated
Comment thread test/test_threads.py Outdated
Comment thread test/test_threads.py Outdated
Test AsyncPeriodicExecutor in a subinterpreter in the async suite,
tighten the code comments, and note that both clients are supported in
the changelog.
Comment thread test/asynchronous/test_periodic_executor.py Outdated
Add test/asynchronous/test_subinterpreters.py with the subinterpreter
and InterpreterPoolExecutor client tests, written once in async style
and mirrored by synchro. Remove them from test_threads.py, which is
not mirrored. Collapse the periodic executor test's duplicated worker
blocks into one block and make its async target a coroutine.
Commit 623ecb0 tightened the comment in the async monitor but did
not regenerate the sync mirror.
…preter

The sync worker blocks on an event set by the target's first run, so
the interpreter is destroyed with the monitor live in its interval
loop. The async worker yields to its loop once, which runs the monitor
task's first step.
@blink1073 blink1073 closed this Sep 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant