lint & format

This commit is contained in:
KronosDev-Pro 2024-11-23 21:17:38 +00:00
parent f70c444833
commit 4a24b3640d
5 changed files with 216 additions and 53 deletions

View File

@ -698,11 +698,7 @@ class Config(Base):
# Custom Backend Server
backend_server_prod: server.CustomBackendServer = server.GunicornBackendServer(
threads=2,
workers=4,
max_requests=100,
max_requests_jitter=25,
timeout=120
threads=2, workers=4, max_requests=100, max_requests_jitter=25, timeout=120
)
backend_server_dev: server.CustomBackendServer = server.UvicornBackendServer(
workers=1,
@ -737,15 +733,21 @@ class Config(Base):
raise ConfigError(
"REDIS_URL is required when using the redis state manager."
)
if any(
getattr(self.get_fields().get(key, None), "default", None) == self.get_value(key)
for key in ("timeout","gunicorn_worker_class", "gunicorn_workers", "gunicorn_max_requests", "gunicorn_max_requests_jitter" )
getattr(self.get_fields().get(key, None), "default", None)
== self.get_value(key)
for key in (
"timeout",
"gunicorn_worker_class",
"gunicorn_workers",
"gunicorn_max_requests",
"gunicorn_max_requests_jitter",
)
):
console.warn(
'The following reflex configuration fields are obsolete: "timeout", "gunicorn_worker_class", "gunicorn_workers", "gunicorn_max_requests", "gunicorn_max_requests_jitter"\nplease update your configuration.'
)
@property
def module(self) -> str:

View File

@ -7,7 +7,7 @@ from abc import abstractmethod
from dataclasses import Field, dataclass
from dataclasses import field as dc_field
from pathlib import Path
from typing import Any, Callable, Sequence, ClassVar
from typing import Any, Callable, ClassVar, Sequence
from reflex import constants
from reflex.constants.base import Env, LogLevel
@ -26,6 +26,12 @@ class CliType:
fmt: `'--env-file {value}'`
value: `'/config.conf'`
result => `'--env-file /config.conf'`
Args:
fmt (str): format
Returns:
ReturnCliTypeFn: function wrapper
"""
def wrapper(value: bool) -> str:
@ -46,6 +52,13 @@ class CliType:
fmt: `'--reload'`
value: `True`
result => `'--reload'`
Args:
fmt (str): format
bool_value (bool): boolean value used for toggle condition
Returns:
ReturnCliTypeFn: function wrapper
"""
def wrapper(value: bool) -> str:
@ -80,6 +93,16 @@ class CliType:
value: `True`
toggle_value: `True`
result => `'--no-access-log'`
Args:
fmt (str): format
toggle_kw (str): keyword used when toggled. Defaults to "no".
toggle_sep (str): separator used when toggled. Defaults to "-".
toggle_value (bool): boolean value used for toggle condition. Defaults to False.
**kwargs: Keyword arguments to pass to the format string function.
Returns:
ReturnCliTypeFn: function wrapper
"""
def wrapper(value: bool) -> str:
@ -102,6 +125,7 @@ class CliType:
Example (Multiple args mode):
fmt: `'--header {value}'`.
data_list: `['X-Forwarded-Proto=https', 'X-Forwarded-For=0.0.0.0']`
join_sep: `None`
result => `'--header \"X-Forwarded-Proto=https\" --header \"X-Forwarded-For=0.0.0.0\"'`
Example (Single args mode):
@ -116,6 +140,14 @@ class CliType:
join_sep (required): `';'`
value_transformer: `lambda value: f'{value[0]}:{value[1]}'`
result => `--headers \"X-Forwarded-Proto:https;X-Forwarded-For:0.0.0.0\"`
Args:
fmt (str): format
join_sep (str): separator used
value_transformer (Callable[[Any], str]): function used for transformer the element
Returns:
ReturnCliTypeFn: function wrapper
"""
def wrapper(values: Sequence[str]) -> str:
@ -139,7 +171,17 @@ def field_(
exclude: bool = False,
**kwargs,
):
"""Custom dataclass field builder."""
"""Custom dataclass field builder.
Args:
default (Any): default value. Defaults to None.
metadata_cli (ReturnCliTypeFn | None): cli wrapper function. Defaults to None.
exclude (bool): used for excluding the field to the server configuration (system field). Defaults to False.
**kwargs: Keyword arguments to pass to the field dataclasses function.
Returns:
Field: return the field dataclasses
"""
params_ = {
"default": default,
"metadata": {"cli": metadata_cli, "exclude": exclude},
@ -156,16 +198,28 @@ def field_(
class CustomBackendServer:
"""BackendServer base."""
_env: ClassVar[Env] = field_(default=Env.DEV, metadata_cli=None, exclude=True, repr = False, init = False)
_app: ClassVar[Any] = field_(default=None, metadata_cli=None, exclude=True, repr = False, init = False)
_app_uri: ClassVar[str] = field_(default="", metadata_cli=None, exclude=True, repr = False, init = False)
_env: ClassVar[Env] = field_(
default=Env.DEV, metadata_cli=None, exclude=True, repr=False, init=False
)
_app: ClassVar[Any] = field_(
default=None, metadata_cli=None, exclude=True, repr=False, init=False
)
_app_uri: ClassVar[str] = field_(
default="", metadata_cli=None, exclude=True, repr=False, init=False
)
@staticmethod
def get_app_module(for_granian_target: bool = False, add_extra_api: bool = False):
def get_app_module(
for_granian_target: bool = False, add_extra_api: bool = False
) -> str:
"""Get the app module for the backend.
Args:
for_granian_target (bool): make the return compatible with Granian. Defaults to False.
add_extra_api (bool): add the keyword "api" at the end (needed for Uvicorn & Granian). Defaults to False.
Returns:
The app module for the backend.
str: The app module for the backend.
"""
import reflex
@ -177,21 +231,41 @@ class CustomBackendServer:
return f"{app_path}:{constants.CompileVars.APP}{f'.{constants.CompileVars.API}' if add_extra_api else ''}"
def get_available_cpus(self) -> int:
"""Get available cpus."""
"""Get available cpus.
Returns:
int: number of available cpu cores
"""
return os.cpu_count() or 1
def get_max_workers(self) -> int:
"""Get max workers."""
"""Get maximum workers.
Returns:
int: get the maximum number of workers
"""
# https://docs.gunicorn.org/en/latest/settings.html#workers
return (os.cpu_count() or 1) * 4 + 1
def get_recommended_workers(self) -> int:
"""Get recommended workers."""
"""Get recommended workers.
Returns:
int: get the recommended number of workers
"""
# https://docs.gunicorn.org/en/latest/settings.html#workers
return (os.cpu_count() or 1) * 2 + 1
def get_max_threads(self, wait_time_ms: int = 50, service_time_ms: int = 5) -> int:
"""Get max threads."""
"""Get maximum threads.
Args:
wait_time_ms (int): the mean waiting duration targeted. Defaults to 50.
service_time_ms (int): the mean working duration. Defaults to 5.
Returns:
int: get the maximum number of threads
"""
# https://engineering.zalando.com/posts/2019/04/how-to-set-an-ideal-thread-pool-size.html
# Brian Goetz formula
return int(self.get_available_cpus() * (1 + wait_time_ms / service_time_ms))
@ -202,7 +276,16 @@ class CustomBackendServer:
wait_time_ms: int = 50,
service_time_ms: int = 5,
) -> int:
"""Get recommended threads."""
"""Get recommended threads.
Args:
target_reqs (int | None): number of requests targeted. Defaults to None.
wait_time_ms (int): the mean waiting duration targeted. Defaults to 50.
service_time_ms (int): the mean working duration. Defaults to 5.
Returns:
int: get the recommended number of threads
"""
# https://engineering.zalando.com/posts/2019/04/how-to-set-an-ideal-thread-pool-size.html
max_available_threads = self.get_max_threads()
@ -221,19 +304,35 @@ class CustomBackendServer:
)
def get_fields(self) -> dict[str, Field]:
"""Return all the fields."""
"""Return all the fields.
Returns:
dict[str, Field]: return the fields dictionary
"""
return self.__dataclass_fields__
def get_values(self) -> dict[str, Any]:
"""Return all values."""
"""Return all values.
Returns:
dict[str, Any]: returns the value of the fields
"""
return {
key: getattr(self, key)
for key, field in self.__dataclass_fields__.items()
if field.metadata["exclude"] is False
}
def is_default_value(self, key, value: Any | None = None) -> bool:
"""Check if the `value` is the same value from default context."""
def is_default_value(self, key: str, value: Any | None = None) -> bool:
"""Check if the `value` is the same value from default context.
Args:
key (str): the name of the field
value (Any | None, optional): the value to check if is equal to the default value. Defaults to None.
Returns:
bool: result of the condition of value are equal to the default value
"""
from dataclasses import MISSING
field = self.get_fields()[key]
@ -250,9 +349,13 @@ class CustomBackendServer:
@abstractmethod
def get_backend_bind(self) -> tuple[str, int]:
"""Return the backend host and port"""
"""Return the backend host and port.
Returns:
tuple[str, int]: The host address and port.
"""
raise NotImplementedError()
@abstractmethod
def check_import(self):
"""Check package importation."""
@ -260,12 +363,23 @@ class CustomBackendServer:
@abstractmethod
def setup(self, host: str, port: int, loglevel: LogLevel, env: Env):
"""Setup."""
"""Setup.
Args:
host (str): host address
port (int): port address
loglevel (LogLevel): log level
env (Env): prod/dev environment
"""
raise NotImplementedError()
@abstractmethod
def run_prod(self):
"""Run in production mode."""
def run_prod(self) -> list[str]:
"""Run in production mode.
Returns:
list[str]: Command ready to be executed
"""
raise NotImplementedError()
@abstractmethod

View File

@ -192,6 +192,11 @@ class GranianBackendServer(CustomBackendServer):
)
def get_backend_bind(self) -> tuple[str, int]:
"""Return the backend host and port.
Returns:
tuple[str, int]: The host address and port.
"""
return self.address, self.port
def check_import(self):
@ -215,13 +220,20 @@ class GranianBackendServer(CustomBackendServer):
sys.exit()
def setup(self, host: str, port: int, loglevel: LogLevel, env: Env):
"""Setup."""
self._app_uri = self.get_app_module(for_granian_target=True, add_extra_api=True)
"""Setup.
Args:
host (str): host address
port (int): port address
loglevel (LogLevel): log level
env (Env): prod/dev environment
"""
self._app_uri = self.get_app_module(for_granian_target=True, add_extra_api=True) # type: ignore
self.log_level = loglevel.value # type: ignore
self.address = host
self.port = port
self.interface = "asgi" # NOTE: prevent obvious error
self._env = env
self._env = env # type: ignore
if env == Env.PROD:
if self.workers == self.get_fields()["workers"].default:
@ -244,7 +256,11 @@ class GranianBackendServer(CustomBackendServer):
self.reload_ignore_dirs = [".web"]
def run_prod(self):
"""Run in production mode."""
"""Run in production mode.
Returns:
list[str]: Command ready to be executed
"""
self.check_import()
command = ["granian"]
@ -261,7 +277,7 @@ class GranianBackendServer(CustomBackendServer):
def run_dev(self):
"""Run in development mode."""
self.check_import()
from granian import Granian
from granian import Granian # type: ignore
exclude_keys = (
"http1_keep_alive",
@ -277,7 +293,8 @@ class GranianBackendServer(CustomBackendServer):
"http2_max_headers_size",
"http2_max_send_buffer_size",
)
self._app = Granian(
self._app = Granian( # type: ignore
**{
**{
key: value
@ -309,5 +326,6 @@ class GranianBackendServer(CustomBackendServer):
self._app.serve()
async def shutdown(self):
"""Shutdown the backend server."""
if self._app and self._env == Env.DEV:
self._app.shutdown()

View File

@ -279,10 +279,14 @@ class GunicornBackendServer(CustomBackendServer):
)
def get_backend_bind(self) -> tuple[str, int]:
"""Return the backend host and port"""
"""Return the backend host and port.
Returns:
tuple[str, int]: The host address and port.
"""
host, port = self.bind[0].split(":")
return host, int(port)
def check_import(self):
"""Check package importation."""
from importlib.util import find_spec
@ -304,11 +308,18 @@ class GunicornBackendServer(CustomBackendServer):
sys.exit()
def setup(self, host: str, port: int, loglevel: LogLevel, env: Env):
"""Setup."""
self._app_uri = f"{self.get_app_module()}()"
"""Setup.
Args:
host (str): host address
port (int): port address
loglevel (LogLevel): log level
env (Env): prod/dev environment
"""
self._app_uri = f"{self.get_app_module()}()" # type: ignore
self.loglevel = loglevel.value # type: ignore
self.bind = [f"{host}:{port}"]
self._env = env
self._env = env # type: ignore
if env == Env.PROD:
if self.workers == self.get_fields()["workers"].default:
@ -328,7 +339,11 @@ class GunicornBackendServer(CustomBackendServer):
self.reload = True
def run_prod(self) -> list[str]:
"""Run in production mode."""
"""Run in production mode.
Returns:
list[str]: Command ready to be executed
"""
self.check_import()
command = ["gunicorn"]
@ -376,13 +391,13 @@ class GunicornBackendServer(CustomBackendServer):
def load(self):
return gunicorn_import_app(self._app_uri)
def stop(self):
from gunicorn.arbiter import Arbiter
Arbiter(self).stop()
self._app = StandaloneApplication(app_uri=self._app_uri, options=options_)
self._app = StandaloneApplication(app_uri=self._app_uri, options=options_) # type: ignore
self._app.run()
async def shutdown(self):

View File

@ -184,9 +184,13 @@ class UvicornBackendServer(CustomBackendServer):
)
def get_backend_bind(self) -> tuple[str, int]:
"""Return the backend host and port"""
"""Return the backend host and port.
Returns:
tuple[str, int]: The host address and port.
"""
return self.host, self.port
def check_import(self):
"""Check package importation."""
from importlib.util import find_spec
@ -210,12 +214,19 @@ class UvicornBackendServer(CustomBackendServer):
sys.exit()
def setup(self, host: str, port: int, loglevel: LogLevel, env: Env):
"""Setup."""
self._app_uri = self.get_app_module(add_extra_api=True)
"""Setup.
Args:
host (str): host address
port (int): port address
loglevel (LogLevel): log level
env (Env): prod/dev environment
"""
self._app_uri = self.get_app_module(add_extra_api=True) # type: ignore
self.log_level = loglevel.value
self.host = host
self.port = port
self._env = env
self._env = env # type: ignore
if env == Env.PROD:
if self.workers == self.get_fields()["workers"].default:
@ -230,8 +241,12 @@ class UvicornBackendServer(CustomBackendServer):
self.reload = True
self.reload_dirs = [str(Path(get_config().app_name))]
def run_prod(self):
"""Run in production mode."""
def run_prod(self) -> list[str]:
"""Run in production mode.
Returns:
list[str]: Command ready to be executed
"""
self.check_import()
command = ["uvicorn"]
@ -255,7 +270,7 @@ class UvicornBackendServer(CustomBackendServer):
if not self.is_default_value(key, value)
}
self._app = Server(
self._app = Server( # type: ignore
config=Config(**options_, app=self._app_uri),
)
self._app.run()
@ -268,4 +283,3 @@ class UvicornBackendServer(CustomBackendServer):
# TODO: hard because currently `*BackendServer` don't execute the server command, he just create it
# if self._env == Env.PROD:
# pass