Add ordering config
This commit is contained in:
parent
ae1669cd8f
commit
7f682cea02
|
@ -3,6 +3,7 @@ import os
|
|||
import signal
|
||||
import sys
|
||||
|
||||
from enum import Enum
|
||||
from typing import Awaitable
|
||||
|
||||
from multidict import CIMultiDict # type: ignore
|
||||
|
@ -19,6 +20,31 @@ except ImportError:
|
|||
pass
|
||||
|
||||
|
||||
# Python 3.11 changed the way Enum formatting works for mixed-in types.
|
||||
if sys.version_info < (3, 11, 0):
|
||||
|
||||
class StrEnum(str, Enum):
|
||||
pass
|
||||
|
||||
else:
|
||||
from enum import StrEnum # type: ignore # noqa
|
||||
|
||||
|
||||
class UpperStrEnum(StrEnum):
|
||||
def _generate_next_value_(name, start, count, last_values):
|
||||
return name.upper()
|
||||
|
||||
def __eq__(self, value: object) -> bool:
|
||||
value = str(value).upper()
|
||||
return super().__eq__(value)
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return hash(self.value)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.value
|
||||
|
||||
|
||||
def enable_windows_color_support():
|
||||
import ctypes
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ from pathlib import Path
|
|||
from typing import Any, Callable, Dict, Optional, Sequence, Union
|
||||
from warnings import filterwarnings
|
||||
|
||||
from sanic.constants import LocalCertCreator
|
||||
from sanic.constants import LocalCertCreator, RestartOrder
|
||||
from sanic.errorpages import DEFAULT_FORMAT, check_error_format
|
||||
from sanic.helpers import Default, _default
|
||||
from sanic.http import Http
|
||||
|
@ -63,6 +63,7 @@ DEFAULT_CONFIG = {
|
|||
"REQUEST_MAX_SIZE": 100000000, # 100 megabytes
|
||||
"REQUEST_TIMEOUT": 60, # 60 seconds
|
||||
"RESPONSE_TIMEOUT": 60, # 60 seconds
|
||||
"RESTART_ORDER": RestartOrder.SHUTDOWN_FIRST,
|
||||
"TLS_CERT_PASSWORD": "",
|
||||
"TOUCHUP": _default,
|
||||
"USE_UVLOOP": _default,
|
||||
|
@ -110,6 +111,7 @@ class Config(dict, metaclass=DescriptorMeta):
|
|||
REQUEST_MAX_SIZE: int
|
||||
REQUEST_TIMEOUT: int
|
||||
RESPONSE_TIMEOUT: int
|
||||
RESTART_ORDER: Union[str, RestartOrder]
|
||||
SERVER_NAME: str
|
||||
TLS_CERT_PASSWORD: str
|
||||
TOUCHUP: Union[Default, bool]
|
||||
|
@ -194,6 +196,10 @@ class Config(dict, metaclass=DescriptorMeta):
|
|||
self.LOCAL_CERT_CREATOR = LocalCertCreator[
|
||||
self.LOCAL_CERT_CREATOR.upper()
|
||||
]
|
||||
elif attr == "RESTART_ORDER" and not isinstance(
|
||||
self.RESTART_ORDER, RestartOrder
|
||||
):
|
||||
self.RESTART_ORDER = RestartOrder[self.RESTART_ORDER.upper()]
|
||||
elif attr == "DEPRECATION_FILTER":
|
||||
self._configure_warnings()
|
||||
|
||||
|
|
|
@ -1,19 +1,9 @@
|
|||
from enum import Enum, auto
|
||||
from enum import auto
|
||||
|
||||
from sanic.compat import UpperStrEnum
|
||||
|
||||
|
||||
class HTTPMethod(str, Enum):
|
||||
def _generate_next_value_(name, start, count, last_values):
|
||||
return name.upper()
|
||||
|
||||
def __eq__(self, value: object) -> bool:
|
||||
value = str(value).upper()
|
||||
return super().__eq__(value)
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return hash(self.value)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.value
|
||||
class HTTPMethod(UpperStrEnum):
|
||||
|
||||
GET = auto()
|
||||
POST = auto()
|
||||
|
@ -24,15 +14,19 @@ class HTTPMethod(str, Enum):
|
|||
DELETE = auto()
|
||||
|
||||
|
||||
class LocalCertCreator(str, Enum):
|
||||
def _generate_next_value_(name, start, count, last_values):
|
||||
return name.upper()
|
||||
class LocalCertCreator(UpperStrEnum):
|
||||
|
||||
AUTO = auto()
|
||||
TRUSTME = auto()
|
||||
MKCERT = auto()
|
||||
|
||||
|
||||
class RestartOrder(UpperStrEnum):
|
||||
|
||||
SHUTDOWN_FIRST = auto()
|
||||
STARTUP_FIRST = auto()
|
||||
|
||||
|
||||
HTTP_METHODS = tuple(HTTPMethod.__members__.values())
|
||||
SAFE_HTTP_METHODS = (HTTPMethod.GET, HTTPMethod.HEAD, HTTPMethod.OPTIONS)
|
||||
IDEMPOTENT_HTTP_METHODS = (
|
||||
|
|
16
sanic/log.py
16
sanic/log.py
|
@ -1,22 +1,10 @@
|
|||
import logging
|
||||
import sys
|
||||
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING, Any, Dict
|
||||
from typing import Any, Dict
|
||||
from warnings import warn
|
||||
|
||||
from sanic.compat import is_atty
|
||||
|
||||
|
||||
# Python 3.11 changed the way Enum formatting works for mixed-in types.
|
||||
if sys.version_info < (3, 11, 0):
|
||||
|
||||
class StrEnum(str, Enum):
|
||||
pass
|
||||
|
||||
else:
|
||||
if not TYPE_CHECKING:
|
||||
from enum import StrEnum
|
||||
from sanic.compat import StrEnum, is_atty
|
||||
|
||||
|
||||
LOGGING_CONFIG_DEFAULTS: Dict[str, Any] = dict( # no cov
|
||||
|
|
|
@ -814,6 +814,7 @@ class StartupMixin(metaclass=SanicMeta):
|
|||
cls._get_context(),
|
||||
(monitor_pub, monitor_sub),
|
||||
worker_state,
|
||||
primary.config.RESTART_ORDER,
|
||||
)
|
||||
if cls.should_auto_reload():
|
||||
reload_dirs: Set[Path] = primary.state.reload_dirs.union(
|
||||
|
|
|
@ -5,6 +5,7 @@ from signal import signal as signal_func
|
|||
from typing import List, Optional
|
||||
|
||||
from sanic.compat import OS_IS_WINDOWS
|
||||
from sanic.constants import RestartOrder
|
||||
from sanic.exceptions import ServerKilled
|
||||
from sanic.log import error_logger, logger
|
||||
from sanic.worker.process import ProcessState, Worker, WorkerProcess
|
||||
|
@ -28,6 +29,7 @@ class WorkerManager:
|
|||
context,
|
||||
monitor_pubsub,
|
||||
worker_state,
|
||||
restart_order: RestartOrder,
|
||||
):
|
||||
self.num_server = number
|
||||
self.context = context
|
||||
|
@ -37,6 +39,7 @@ class WorkerManager:
|
|||
self.worker_state = worker_state
|
||||
self.worker_state[self.MAIN_IDENT] = {"pid": self.pid}
|
||||
self.terminated = False
|
||||
self.restart_order = restart_order
|
||||
|
||||
if number == 0:
|
||||
raise RuntimeError("Cannot serve with no workers")
|
||||
|
@ -55,7 +58,14 @@ class WorkerManager:
|
|||
def manage(self, ident, func, kwargs, transient=False):
|
||||
container = self.transient if transient else self.durable
|
||||
container.append(
|
||||
Worker(ident, func, kwargs, self.context, self.worker_state)
|
||||
Worker(
|
||||
ident,
|
||||
func,
|
||||
kwargs,
|
||||
self.context,
|
||||
self.worker_state,
|
||||
self.restart_order,
|
||||
)
|
||||
)
|
||||
|
||||
def run(self):
|
||||
|
|
|
@ -7,6 +7,7 @@ from signal import SIGINT
|
|||
from threading import Thread
|
||||
from typing import Any, Dict, Set
|
||||
|
||||
from sanic.constants import RestartOrder
|
||||
from sanic.log import Colors, logger
|
||||
|
||||
|
||||
|
@ -28,13 +29,22 @@ class ProcessState(IntEnum):
|
|||
class WorkerProcess:
|
||||
SERVER_LABEL = "Server"
|
||||
|
||||
def __init__(self, factory, name, target, kwargs, worker_state):
|
||||
def __init__(
|
||||
self,
|
||||
factory,
|
||||
name,
|
||||
target,
|
||||
kwargs,
|
||||
worker_state,
|
||||
restart_order: RestartOrder,
|
||||
):
|
||||
self.state = ProcessState.IDLE
|
||||
self.factory = factory
|
||||
self.name = name
|
||||
self.target = target
|
||||
self.kwargs = kwargs
|
||||
self.worker_state = worker_state
|
||||
self.restart_order = restart_order
|
||||
if self.name not in self.worker_state:
|
||||
self.worker_state[self.name] = {
|
||||
"server": self.SERVER_LABEL in self.name
|
||||
|
@ -96,8 +106,11 @@ class WorkerProcess:
|
|||
self.name,
|
||||
self.pid,
|
||||
)
|
||||
self._old_process = self._current_process
|
||||
self.set_state(ProcessState.RESTARTING, force=True)
|
||||
if self.restart_order is RestartOrder.SHUTDOWN_FIRST:
|
||||
self._current_process.terminate()
|
||||
else:
|
||||
self._old_process = self._current_process
|
||||
self.kwargs.update(
|
||||
{"config": {k.upper(): v for k, v in kwargs.items()}}
|
||||
)
|
||||
|
@ -107,6 +120,7 @@ class WorkerProcess:
|
|||
except AttributeError:
|
||||
raise RuntimeError("Restart failed")
|
||||
|
||||
if self.restart_order is RestartOrder.STARTUP_FIRST:
|
||||
termination_thread = Thread(target=self.wait_to_terminate)
|
||||
termination_thread.start()
|
||||
|
||||
|
@ -118,7 +132,7 @@ class WorkerProcess:
|
|||
}
|
||||
|
||||
def wait_to_terminate(self):
|
||||
# TODO: Add a timeout
|
||||
# TODO: Add a timeout?
|
||||
while self.state is not ProcessState.ACKED:
|
||||
...
|
||||
else:
|
||||
|
@ -163,6 +177,7 @@ class Worker:
|
|||
server_settings,
|
||||
context: BaseContext,
|
||||
worker_state: Dict[str, Any],
|
||||
restart_order: RestartOrder,
|
||||
):
|
||||
self.ident = f"{self.WORKER_PREFIX}{ident}"
|
||||
self.context = context
|
||||
|
@ -170,6 +185,7 @@ class Worker:
|
|||
self.server_settings = server_settings
|
||||
self.worker_state = worker_state
|
||||
self.processes: Set[WorkerProcess] = set()
|
||||
self.restart_order = restart_order
|
||||
self.create_process()
|
||||
|
||||
def create_process(self) -> WorkerProcess:
|
||||
|
@ -179,6 +195,7 @@ class Worker:
|
|||
target=self.serve,
|
||||
kwargs={**self.server_settings},
|
||||
worker_state=self.worker_state,
|
||||
restart_order=self.restart_order,
|
||||
)
|
||||
self.processes.add(process)
|
||||
return process
|
||||
|
|
Loading…
Reference in New Issue
Block a user