Set multiprocessing start method early (#2776)

This commit is contained in:
Adam Hopkins 2023-07-09 22:34:15 +03:00 committed by GitHub
parent 4a2b82e42e
commit 666371bb92
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 35 additions and 6 deletions

View File

@ -29,6 +29,7 @@ from typing import (
AnyStr,
Awaitable,
Callable,
ClassVar,
Coroutine,
Deque,
Dict,
@ -158,8 +159,8 @@ class Sanic(StaticHandleMixin, BaseSanic, StartupMixin, metaclass=TouchUpMeta):
"websocket_tasks",
)
_app_registry: Dict[str, "Sanic"] = {}
test_mode = False
_app_registry: ClassVar[Dict[str, "Sanic"]] = {}
test_mode: ClassVar[bool] = False
def __init__(
self,

View File

@ -16,7 +16,13 @@ from asyncio import (
from contextlib import suppress
from functools import partial
from importlib import import_module
from multiprocessing import Manager, Pipe, get_context
from multiprocessing import (
Manager,
Pipe,
get_context,
get_start_method,
set_start_method,
)
from multiprocessing.context import BaseContext
from pathlib import Path
from socket import SHUT_RDWR, socket
@ -25,6 +31,7 @@ from typing import (
TYPE_CHECKING,
Any,
Callable,
ClassVar,
Dict,
List,
Mapping,
@ -81,13 +88,17 @@ else: # no cov
class StartupMixin(metaclass=SanicMeta):
_app_registry: Dict[str, Sanic]
_app_registry: ClassVar[Dict[str, Sanic]]
config: Config
listeners: Dict[str, List[ListenerType[Any]]]
state: ApplicationState
websocket_enabled: bool
multiplexer: WorkerMultiplexer
start_method: StartMethod = _default
test_mode: ClassVar[bool]
start_method: ClassVar[StartMethod] = _default
START_METHOD_SET: ClassVar[bool] = False
def setup_loop(self):
if not self.asgi:
@ -691,11 +702,26 @@ class StartupMixin(metaclass=SanicMeta):
else "spawn"
)
@classmethod
def _set_startup_method(cls) -> None:
if cls.START_METHOD_SET and not cls.test_mode:
return
method = cls._get_startup_method()
set_start_method(method, force=cls.test_mode)
cls.START_METHOD_SET = True
@classmethod
def _get_context(cls) -> BaseContext:
method = cls._get_startup_method()
logger.debug("Creating multiprocessing context using '%s'", method)
return get_context(method)
actual = get_start_method()
if method != actual:
raise RuntimeError(
f"Start method '{method}' was requested, but '{actual}' "
"was actually set."
)
return get_context()
@classmethod
def serve(
@ -705,6 +731,7 @@ class StartupMixin(metaclass=SanicMeta):
app_loader: Optional[AppLoader] = None,
factory: Optional[Callable[[], Sanic]] = None,
) -> None:
cls._set_startup_method()
os.environ["SANIC_MOTD_OUTPUT"] = "true"
apps = list(cls._app_registry.values())
if factory:

View File

@ -3,6 +3,7 @@ import logging
import pytest
import sanic
from sanic import Sanic
from sanic.config import Config
from sanic.errorpages import TextRenderer, exception_response, guess_mime