Repository navigation
fix: pin multi-concurrent worker start method to fork - #232
Closed
anzheyazzz wants to merge 2 commits into
Closed
anzheyazzz wants to merge 2 commits into
anzheyazzz wants to merge 2 commits into
Conversation
multiprocessing.Process used the interpreter default start method, which is fork on 3.13 and forkserver on 3.14+, so the worker process model differed by runtime. Pin "fork" via get_context so workers are direct children of the runtime process on every version and the parent default is left untouched for customer code.
anzheyazzz
marked this pull request as ready for review
October 15, 2026 08:05
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.
Issue #, if available: n/a
Description of changes:
In multi-concurrent (Lambda Managed Instances) mode
MultiConcurrentRunner.run_concurrentcreates workers withmultiprocessing.Process, which uses the interpreter's default start method. That default isforkon Python 3.13 and earlier andforkserveron 3.14 and later, so the same RIC produces two different process models depending on the runtime:fork)forkserver)forkserverprocess the RIC does not manageThis PR pins the start method to
forkviamultiprocessing.get_context("fork"), so every supported runtime behaves the way 3.13 does today.forkis chosen overspawn/forkserverbecause it keeps the worker a direct child of the RIC process with its memory image, which is what makes copy-on-write sharing of anything loaded in the parent possible later;spawn/forkserverwould close that door.get_contextis used instead ofset_start_methodso the pin applies only to the processes the RIC creates and does not change the default for customer code that usesmultiprocessinginside the handler.The pin introduces two invariants that the parent must keep before
run_concurrentforks, both true today and now asserted by tests: the parent is single-threaded (fork copies only the calling thread, and CPython 3.12+ warns on fork from a multi-threaded process), and the parent has not imported customer code (underforka module already insys.modulesis not re-executed in the worker, which is the mechanism behind the 4.1.0 regression that 4.2.1 reverted). Any future pre-fork feature has to respect both.Behavior change: none on 3.13 and earlier. On 3.14+ the forkserver process disappears and workers become direct children of the RIC process; worker
os.getppid()changes accordingly. No change on the standard on-demand path.Tests:
test_run_concurrent_pins_fork_start_method:get_contextis called with"fork"and workers are created from that context.test_workers_are_forked_children_regardless_of_default_start_method(real processes): with the interpreter default forced toforkserver, every worker still reports the test process as its parent, the parent had one thread at fork time, and a module placed insys.modulesbefore the fork is present in each worker. Fails without the pin ([0, 0, 0] != [1, 1, 1]on the inherited-module check).run_concurrenttests updated to patchmultiprocessing.get_contextinstead ofmultiprocessing.Process./var/runtime/bootstrap.py), no forkserver process exists, and the parent has exactly one thread at fork time. On the shipped 4.1.0 the 3.14 worker's parent was a forkserver process.Target (OCI, Managed Runtime, both): both (multi-concurrent mode only)
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
Proposed
RELEASE.CHANGELOG.mdentry (not included in this PR; left for the release bump):4.2.2forkin multi-concurrent (Lambda Managed Instances) mode instead of inheriting the interpreter default, which changed fromforktoforkserverin Python 3.14. Workers are now direct children of the runtime process on every supported Python version. No behavior change on 3.13 and earlier; no impact on the standard on-demand path.