fix(daemon_pool): support Python 3.14 ThreadPoolExecutor WorkerContext signature - #63780
Closed
xxiaoxiong wants to merge 1 commit into
Closed
fix(daemon_pool): support Python 3.14 ThreadPoolExecutor WorkerContext signature#63780xxiaoxiong wants to merge 1 commit into
xxiaoxiong wants to merge 1 commit into
Conversation
…t signature
Python 3.14 refactored concurrent.futures.ThreadPoolExecutor: the
`_worker` target now takes `(executor_ref, ctx, work_queue)` where `ctx`
is a WorkerContext produced by `self._create_worker_context()`, replacing
the legacy `(executor_ref, work_queue, initializer, initargs)` signature.
`__init__` also no longer sets `self._initializer` / `self._initargs`.
`DaemonThreadPoolExecutor._adjust_thread_count` still passed the legacy
4-arg shape, so on 3.14 every spawn raised:
AttributeError: 'DaemonThreadPoolExecutor' object has no attribute '_initializer'
This breaks every daemon-pool consumer on 3.14+:
- tools/delegate_tool.py (subagent batch execution + timeout wrappers)
- tools/async_delegation.py (background delegate_task dispatch)
- tools/skills_hub.py (catalog fan-out)
When the daemon pool cannot spawn, delegate_task's batch path collapses
to a synchronous inline run, destroying the parallelism the user asked
for and silently wedging subagent fan-out.
Fix
---
Detect the new layout once at import time by inspecting `_worker`'s
signature (param count 3 = 3.14+, 4 = 3.8–3.13). The `_worker` signature
is the load-bearing contract: it's stable across patch releases and
immune to the instance-vs-class attribute pitfall that breaks
`hasattr(ThreadPoolExecutor, '_initializer')` (3.11 only sets it on
instances, so the class check is False on every version).
The 3.14+ branch passes `self._create_worker_context()` as `ctx`; the
3.8–3.13 branch is unchanged. Daemon behavior (daemon=True, no
_threads_queues registration) is preserved on both paths.
Tests
-----
tests/tools/test_daemon_pool.py:
- existing 4 tests still pass on 3.8–3.13 (unchanged behavior).
- new test_python_314_worker_context_signature_does_not_crash guards
the regression: submit must not raise AttributeError, the worker
must be daemon, must not be in `_threads_queues`, and the
initializer must run via the WorkerContext path. Skips on 3.11–3.13.
- new test_python_314_submit_many_tasks_exercises_reused_workers
guards against a worker-context-tied-to-first-submit regression on
the idle-semaphore reuse path. Runs on all versions.
Verified
--------
Python 3.11.15: 5 passed, 1 skipped
Python 3.14.4: 6 passed (regression test now executes)
Python 3.11.15: 27 passed in tests/{test_delegate_cascade_49148,
tools/test_async_delegation}.py — no regressions to
delegate_task / async delegation paths.
Closes NousResearch#63769.
Collaborator
Duplicate of #57459 (earliest open) — same |
Author
|
Closing — Duplicate of #57459 (Python 3.14 daemon_pool compat, same site/issue, different probe mechanism) |
13 tasks
This was referenced Aug 3, 2026
Open
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Python 3.14 refactored
concurrent.futures.ThreadPoolExecutor: the_workertarget now takes(executor_ref, ctx, work_queue)wherectxis aWorkerContextproduced byself._create_worker_context(), replacing the legacy(executor_ref, work_queue, initializer, initargs)signature.__init__also no longer setsself._initializer/self._initargs.DaemonThreadPoolExecutor._adjust_thread_countstill passed the legacy 4-arg shape, so on Python 3.14 every spawn raised:This breaks every daemon-pool consumer on 3.14+:
tools/delegate_tool.py(subagent batch execution + timeout wrappers)tools/async_delegation.py(background delegate_task dispatch)tools/skills_hub.py(catalog fan-out)When the daemon pool cannot spawn,
delegate_task's batch path collapses to a synchronous inline run, destroying parallelism and silently wedging subagent fan-out.Fixes #63769.
Fix
Detect the new layout once at import time by inspecting
_worker's signature (param count 3 = 3.14+, 4 = 3.8–3.13). The_workersignature is the load-bearing contract: stable across patch releases and immune to the instance-vs-class attribute pitfall that breakshasattr(ThreadPoolExecutor, '_initializer')(3.11 only sets it on instances, so the class check isFalseon every version).The 3.14+ branch passes
self._create_worker_context()asctx; the 3.8–3.13 branch is unchanged. Daemon behavior (daemon=True, no_threads_queuesregistration) is preserved on both paths.Testing
tests/tools/test_daemon_pool.py:test_python_314_worker_context_signature_does_not_crash— guards the regression: submit must not raiseAttributeError, worker must be daemon, must not be in_threads_queues, initializer must run via WorkerContext. Skips on 3.11–3.13.test_python_314_submit_many_tasks_exercises_reused_workers— guards against worker-context-tied-to-first-submit regression on the idle-semaphore reuse path. Runs on all versions.Verified on both runtimes
Notes
_worker's function signatur e viainspect.signature, not class-level attribute probes — this is the only reliable cross-version check._PY314_PLUSis a module-level constant computed once at import time, so the hot path (_adjust_thread_count) stays branch-lite._supports_worker_context()re-uses_PY314_PLUSso the gate and dispatch logic stay in lockstep.