Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion billiard/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,14 @@ def _check_available(self):
'spawn': SpawnContext(),
'forkserver': ForkServerContext(),
}
_default_context = DefaultContext(_concrete_contexts['fork'])
if sys.platform == 'darwin':
# bpo-33725: running arbitrary code after fork() is no longer
# reliable on macOS since macOS 10.14 (Mojave). Use spawn by
# default instead.
# See https://github.com/celery/celery/issues/9894
_default_context = DefaultContext(_concrete_contexts['spawn'])
else:
_default_context = DefaultContext(_concrete_contexts['fork'])

else:

Expand Down
55 changes: 55 additions & 0 deletions t/unit/test_context.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import subprocess
import sys


def _get_default_context_attr(platform, attr):
"""Run a subprocess that patches sys.platform before importing billiard.

This exercises the actual import-time conditional without corrupting
the module state of the current process.
"""
result = subprocess.run(
[sys.executable, '-c',
'import unittest.mock; '
f'unittest.mock.patch("sys.platform", {platform!r}).start(); '
'import billiard.context; '
f'print(getattr(billiard.context._default_context, {attr!r})())'],
capture_output=True, text=True,
)
assert result.returncode == 0, result.stderr
return result.stdout.strip()


class test_default_context_darwin:
"""Tests that macOS defaults to spawn, matching CPython (bpo-33725)."""

def test_default_start_method_is_spawn_on_darwin(self):
method = _get_default_context_attr('darwin', 'get_start_method')
assert method == 'spawn'

def test_default_start_method_is_fork_on_linux(self):
method = _get_default_context_attr('linux', 'get_start_method')
assert method == 'fork'

def test_set_start_method_override_on_darwin(self):
result = subprocess.run(
[sys.executable, '-c',
'import unittest.mock; '
'unittest.mock.patch("sys.platform", "darwin").start(); '
'import billiard.context; '
'ctx = billiard.context._default_context; '
'assert ctx.get_start_method() == "spawn"; '
'ctx.set_start_method("fork", force=True); '
'print(ctx.get_start_method())'],
capture_output=True, text=True,
)
assert result.returncode == 0, result.stderr
assert result.stdout.strip() == 'fork'

def test_forking_is_enabled_false_on_darwin(self):
enabled = _get_default_context_attr('darwin', 'forking_is_enabled')
assert enabled == 'False'

def test_forking_is_enabled_true_on_linux(self):
enabled = _get_default_context_attr('linux', 'forking_is_enabled')
assert enabled == 'True'