Set multiprocessing start method early (#2776)
This commit is contained in:
parent
4a2b82e42e
commit
666371bb92
|
@ -29,6 +29,7 @@ from typing import (
|
||||||
AnyStr,
|
AnyStr,
|
||||||
Awaitable,
|
Awaitable,
|
||||||
Callable,
|
Callable,
|
||||||
|
ClassVar,
|
||||||
Coroutine,
|
Coroutine,
|
||||||
Deque,
|
Deque,
|
||||||
Dict,
|
Dict,
|
||||||
|
@ -158,8 +159,8 @@ class Sanic(StaticHandleMixin, BaseSanic, StartupMixin, metaclass=TouchUpMeta):
|
||||||
"websocket_tasks",
|
"websocket_tasks",
|
||||||
)
|
)
|
||||||
|
|
||||||
_app_registry: Dict[str, "Sanic"] = {}
|
_app_registry: ClassVar[Dict[str, "Sanic"]] = {}
|
||||||
test_mode = False
|
test_mode: ClassVar[bool] = False
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
|
|
@ -16,7 +16,13 @@ from asyncio import (
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from importlib import import_module
|
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 multiprocessing.context import BaseContext
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from socket import SHUT_RDWR, socket
|
from socket import SHUT_RDWR, socket
|
||||||
|
@ -25,6 +31,7 @@ from typing import (
|
||||||
TYPE_CHECKING,
|
TYPE_CHECKING,
|
||||||
Any,
|
Any,
|
||||||
Callable,
|
Callable,
|
||||||
|
ClassVar,
|
||||||
Dict,
|
Dict,
|
||||||
List,
|
List,
|
||||||
Mapping,
|
Mapping,
|
||||||
|
@ -81,13 +88,17 @@ else: # no cov
|
||||||
|
|
||||||
|
|
||||||
class StartupMixin(metaclass=SanicMeta):
|
class StartupMixin(metaclass=SanicMeta):
|
||||||
_app_registry: Dict[str, Sanic]
|
_app_registry: ClassVar[Dict[str, Sanic]]
|
||||||
|
|
||||||
config: Config
|
config: Config
|
||||||
listeners: Dict[str, List[ListenerType[Any]]]
|
listeners: Dict[str, List[ListenerType[Any]]]
|
||||||
state: ApplicationState
|
state: ApplicationState
|
||||||
websocket_enabled: bool
|
websocket_enabled: bool
|
||||||
multiplexer: WorkerMultiplexer
|
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):
|
def setup_loop(self):
|
||||||
if not self.asgi:
|
if not self.asgi:
|
||||||
|
@ -691,11 +702,26 @@ class StartupMixin(metaclass=SanicMeta):
|
||||||
else "spawn"
|
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
|
@classmethod
|
||||||
def _get_context(cls) -> BaseContext:
|
def _get_context(cls) -> BaseContext:
|
||||||
method = cls._get_startup_method()
|
method = cls._get_startup_method()
|
||||||
logger.debug("Creating multiprocessing context using '%s'", 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
|
@classmethod
|
||||||
def serve(
|
def serve(
|
||||||
|
@ -705,6 +731,7 @@ class StartupMixin(metaclass=SanicMeta):
|
||||||
app_loader: Optional[AppLoader] = None,
|
app_loader: Optional[AppLoader] = None,
|
||||||
factory: Optional[Callable[[], Sanic]] = None,
|
factory: Optional[Callable[[], Sanic]] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
cls._set_startup_method()
|
||||||
os.environ["SANIC_MOTD_OUTPUT"] = "true"
|
os.environ["SANIC_MOTD_OUTPUT"] = "true"
|
||||||
apps = list(cls._app_registry.values())
|
apps = list(cls._app_registry.values())
|
||||||
if factory:
|
if factory:
|
||||||
|
|
|
@ -3,6 +3,7 @@ import logging
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import sanic
|
import sanic
|
||||||
|
|
||||||
from sanic import Sanic
|
from sanic import Sanic
|
||||||
from sanic.config import Config
|
from sanic.config import Config
|
||||||
from sanic.errorpages import TextRenderer, exception_response, guess_mime
|
from sanic.errorpages import TextRenderer, exception_response, guess_mime
|
||||||
|
|
Loading…
Reference in New Issue
Block a user