[FIX] - formatter/linter, prevent failed backend server start
This commit is contained in:
parent
02858dc425
commit
1ce3569fbf
@ -745,8 +745,11 @@ class Config(Base):
|
||||
"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.'
|
||||
console.deprecate(
|
||||
'The following reflex configuration fields are obsolete: "timeout", "gunicorn_worker_class", "gunicorn_workers", "gunicorn_max_requests", "gunicorn_max_requests_jitter"\nplease update your configuration.',
|
||||
reason="Use `config.backend_server_dev` or `config.backend_server_prod` instead in your `rxconfig.py`.",
|
||||
deprecation_version="0.7.x",
|
||||
removal_version="x.x.x",
|
||||
)
|
||||
|
||||
@property
|
||||
|
@ -1,4 +1,5 @@
|
||||
"""The base for CustomBackendServer."""
|
||||
# ruff: noqa: RUF009
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@ -297,11 +298,7 @@ class CustomBackendServer:
|
||||
else:
|
||||
need_threads = self.get_max_threads(wait_time_ms, service_time_ms)
|
||||
|
||||
return int(
|
||||
max_available_threads
|
||||
if need_threads > max_available_threads
|
||||
else need_threads
|
||||
)
|
||||
return int(min(need_threads, max_available_threads))
|
||||
|
||||
def get_fields(self) -> dict[str, Field]:
|
||||
"""Return all the fields.
|
||||
|
@ -1,8 +1,8 @@
|
||||
"""The GranianBackendServer."""
|
||||
# ruff: noqa: RUF009
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from dataclasses import dataclass
|
||||
from dataclasses import field as dc_field
|
||||
from pathlib import Path
|
||||
@ -200,7 +200,11 @@ class GranianBackendServer(CustomBackendServer):
|
||||
return self.address, self.port
|
||||
|
||||
def check_import(self):
|
||||
"""Check package importation."""
|
||||
"""Check package importation.
|
||||
|
||||
Raises:
|
||||
ImportError: raise when some required packaging missing.
|
||||
"""
|
||||
from importlib.util import find_spec
|
||||
|
||||
errors: list[str] = []
|
||||
@ -217,7 +221,7 @@ class GranianBackendServer(CustomBackendServer):
|
||||
|
||||
if errors:
|
||||
console.error("\n".join(errors))
|
||||
sys.exit()
|
||||
raise ImportError()
|
||||
|
||||
def setup(self, host: str, port: int, loglevel: LogLevel, env: Env):
|
||||
"""Setup.
|
||||
@ -228,6 +232,7 @@ class GranianBackendServer(CustomBackendServer):
|
||||
loglevel (LogLevel): log level
|
||||
env (Env): prod/dev environment
|
||||
"""
|
||||
self.check_import()
|
||||
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
|
||||
@ -235,25 +240,17 @@ class GranianBackendServer(CustomBackendServer):
|
||||
self.interface = "asgi" # NOTE: prevent obvious error
|
||||
self._env = env # type: ignore
|
||||
|
||||
if env == Env.PROD:
|
||||
if self.workers == self.get_fields()["workers"].default:
|
||||
self.workers = self.get_recommended_workers()
|
||||
else:
|
||||
if self.workers > (max_workers := self.get_max_workers()):
|
||||
self.workers = max_workers
|
||||
if self.workers == self.get_fields()["workers"].default:
|
||||
self.workers = self.get_recommended_workers()
|
||||
else:
|
||||
if self.workers > (max_workers := self.get_max_workers()):
|
||||
self.workers = max_workers
|
||||
|
||||
if self.threads == self.get_fields()["threads"].default:
|
||||
self.threads = self.get_recommended_threads()
|
||||
else:
|
||||
if self.threads > (max_threads := self.get_max_threads()):
|
||||
self.threads = max_threads
|
||||
|
||||
if env == Env.DEV:
|
||||
from reflex.config import get_config # prevent circular import
|
||||
|
||||
self.reload = True
|
||||
self.reload_paths = [Path(get_config().app_name)]
|
||||
self.reload_ignore_dirs = [".web"]
|
||||
if self.threads == self.get_fields()["threads"].default:
|
||||
self.threads = self.get_recommended_threads()
|
||||
else:
|
||||
if self.threads > (max_threads := self.get_max_threads()):
|
||||
self.threads = max_threads
|
||||
|
||||
def run_prod(self):
|
||||
"""Run in production mode.
|
||||
@ -272,7 +269,7 @@ class GranianBackendServer(CustomBackendServer):
|
||||
):
|
||||
command += field.metadata["cli"](value).split(" ")
|
||||
|
||||
return command + [self._app_uri]
|
||||
return [*command, self._app_uri]
|
||||
|
||||
def run_dev(self):
|
||||
"""Run in development mode."""
|
||||
|
@ -1,8 +1,8 @@
|
||||
"""The GunicornBackendServer."""
|
||||
# ruff: noqa: RUF009
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Callable, Literal
|
||||
|
||||
@ -288,7 +288,11 @@ class GunicornBackendServer(CustomBackendServer):
|
||||
return host, int(port)
|
||||
|
||||
def check_import(self):
|
||||
"""Check package importation."""
|
||||
"""Check package importation.
|
||||
|
||||
Raises:
|
||||
ImportError: raise when some required packaging missing.
|
||||
"""
|
||||
from importlib.util import find_spec
|
||||
|
||||
errors: list[str] = []
|
||||
@ -305,7 +309,7 @@ class GunicornBackendServer(CustomBackendServer):
|
||||
|
||||
if errors:
|
||||
console.error("\n".join(errors))
|
||||
sys.exit()
|
||||
raise ImportError()
|
||||
|
||||
def setup(self, host: str, port: int, loglevel: LogLevel, env: Env):
|
||||
"""Setup.
|
||||
@ -316,27 +320,23 @@ class GunicornBackendServer(CustomBackendServer):
|
||||
loglevel (LogLevel): log level
|
||||
env (Env): prod/dev environment
|
||||
"""
|
||||
self.check_import()
|
||||
self._app_uri = f"{self.get_app_module()}()" # type: ignore
|
||||
self.loglevel = loglevel.value # type: ignore
|
||||
self.bind = [f"{host}:{port}"]
|
||||
self._env = env # type: ignore
|
||||
|
||||
if env == Env.PROD:
|
||||
if self.workers == self.get_fields()["workers"].default:
|
||||
self.workers = self.get_recommended_workers()
|
||||
else:
|
||||
if self.workers > (max_threads := self.get_max_workers()):
|
||||
self.workers = max_threads
|
||||
if self.workers == self.get_fields()["workers"].default:
|
||||
self.workers = self.get_recommended_workers()
|
||||
else:
|
||||
if self.workers > (max_threads := self.get_max_workers()):
|
||||
self.workers = max_threads
|
||||
|
||||
if self.threads == self.get_fields()["threads"].default:
|
||||
self.threads = self.get_recommended_threads()
|
||||
else:
|
||||
if self.threads > (max_threads := self.get_max_threads()):
|
||||
self.threads = max_threads
|
||||
self.preload_app = True
|
||||
|
||||
if env == Env.DEV:
|
||||
self.reload = True
|
||||
if self.threads == self.get_fields()["threads"].default:
|
||||
self.threads = self.get_recommended_threads()
|
||||
else:
|
||||
if self.threads > (max_threads := self.get_max_threads()):
|
||||
self.threads = max_threads
|
||||
|
||||
def run_prod(self) -> list[str]:
|
||||
"""Run in production mode.
|
||||
@ -355,7 +355,7 @@ class GunicornBackendServer(CustomBackendServer):
|
||||
):
|
||||
command += field.metadata["cli"](value).split(" ")
|
||||
|
||||
return command + [self._app_uri]
|
||||
return [*command, self._app_uri]
|
||||
|
||||
def run_dev(self):
|
||||
"""Run in development mode."""
|
||||
@ -404,7 +404,3 @@ class GunicornBackendServer(CustomBackendServer):
|
||||
"""Shutdown the backend server."""
|
||||
if self._app and self._env == Env.DEV:
|
||||
self._app.stop() # type: ignore
|
||||
|
||||
# TODO: complicated because currently `*BackendServer` don't execute the server command, he just create it
|
||||
# if self._env == Env.PROD:
|
||||
# pass
|
||||
|
@ -1,4 +1,5 @@
|
||||
"""The UvicornBackendServer."""
|
||||
# ruff: noqa: RUF009
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@ -6,10 +7,8 @@ from __future__ import annotations
|
||||
import asyncio
|
||||
import os
|
||||
import ssl
|
||||
import sys
|
||||
from configparser import RawConfigParser
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import IO, Any, Awaitable, Callable
|
||||
|
||||
from uvicorn import Config, Server
|
||||
@ -192,7 +191,11 @@ class UvicornBackendServer(CustomBackendServer):
|
||||
return self.host, self.port
|
||||
|
||||
def check_import(self):
|
||||
"""Check package importation."""
|
||||
"""Check package importation.
|
||||
|
||||
Raises:
|
||||
ImportError: raise when some required packaging missing.
|
||||
"""
|
||||
from importlib.util import find_spec
|
||||
|
||||
errors: list[str] = []
|
||||
@ -211,7 +214,7 @@ class UvicornBackendServer(CustomBackendServer):
|
||||
|
||||
if errors:
|
||||
console.error("\n".join(errors))
|
||||
sys.exit()
|
||||
raise ImportError()
|
||||
|
||||
def setup(self, host: str, port: int, loglevel: LogLevel, env: Env):
|
||||
"""Setup.
|
||||
@ -222,24 +225,18 @@ class UvicornBackendServer(CustomBackendServer):
|
||||
loglevel (LogLevel): log level
|
||||
env (Env): prod/dev environment
|
||||
"""
|
||||
self.check_import()
|
||||
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 # type: ignore
|
||||
|
||||
if env == Env.PROD:
|
||||
if self.workers == self.get_fields()["workers"].default:
|
||||
self.workers = self.get_recommended_workers()
|
||||
else:
|
||||
if self.workers > (max_workers := self.get_max_workers()):
|
||||
self.workers = max_workers
|
||||
|
||||
if env == Env.DEV:
|
||||
from reflex.config import get_config # prevent circular import
|
||||
|
||||
self.reload = True
|
||||
self.reload_dirs = [str(Path(get_config().app_name))]
|
||||
if self.workers == self.get_fields()["workers"].default:
|
||||
self.workers = self.get_recommended_workers()
|
||||
else:
|
||||
if self.workers > (max_workers := self.get_max_workers()):
|
||||
self.workers = max_workers
|
||||
|
||||
def run_prod(self) -> list[str]:
|
||||
"""Run in production mode.
|
||||
@ -258,7 +255,7 @@ class UvicornBackendServer(CustomBackendServer):
|
||||
):
|
||||
command += field.metadata["cli"](value).split(" ")
|
||||
|
||||
return command + [self._app_uri]
|
||||
return [*command, self._app_uri]
|
||||
|
||||
def run_dev(self):
|
||||
"""Run in development mode."""
|
||||
@ -279,7 +276,3 @@ class UvicornBackendServer(CustomBackendServer):
|
||||
"""Shutdown the backend server."""
|
||||
if self._app and self._env == Env.DEV:
|
||||
self._app.shutdown() # type: ignore
|
||||
|
||||
# TODO: hard because currently `*BackendServer` don't execute the server command, he just create it
|
||||
# if self._env == Env.PROD:
|
||||
# pass
|
||||
|
@ -10,6 +10,7 @@ import re
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from threading import Barrier, Event
|
||||
from urllib.parse import urljoin
|
||||
|
||||
import psutil
|
||||
@ -22,6 +23,8 @@ from reflex.utils.prerequisites import get_web_dir
|
||||
|
||||
# For uvicorn windows bug fix (#2335)
|
||||
frontend_process = None
|
||||
barrier = Barrier(2)
|
||||
failed_start_signal = Event()
|
||||
|
||||
|
||||
def detect_package_change(json_file_path: Path) -> str:
|
||||
@ -61,8 +64,14 @@ def kill(proc_pid: int):
|
||||
process.kill()
|
||||
|
||||
|
||||
def notify_backend():
|
||||
"""Output a string notifying where the backend is running."""
|
||||
def notify_backend(only_backend: bool = False):
|
||||
"""Output a string notifying where the backend is running.
|
||||
|
||||
Args:
|
||||
only_backend: Whether the frontend is present.
|
||||
"""
|
||||
if not only_backend:
|
||||
barrier.wait()
|
||||
console.print(
|
||||
f"Backend running at: [bold green]http://0.0.0.0:{get_config().backend_port}[/bold green]"
|
||||
)
|
||||
@ -110,8 +119,14 @@ def run_process_and_launch_url(run_command: list[str], backend_present=True):
|
||||
console.print(
|
||||
f"App running at: [bold green]{url}[/bold green]{' (Frontend-only mode)' if not backend_present else ''}"
|
||||
)
|
||||
|
||||
if backend_present:
|
||||
notify_backend()
|
||||
barrier.wait()
|
||||
if failed_start_signal.is_set():
|
||||
kill(process.pid)
|
||||
process = None
|
||||
break
|
||||
|
||||
first_run = False
|
||||
else:
|
||||
console.print("New packages detected: Updating app...")
|
||||
@ -130,7 +145,7 @@ def run_process_and_launch_url(run_command: list[str], backend_present=True):
|
||||
kill(process.pid)
|
||||
process = None
|
||||
break # for line in process.stdout
|
||||
if process is not None:
|
||||
if (process is not None) or (failed_start_signal.is_set() and process is None):
|
||||
break # while True
|
||||
|
||||
|
||||
@ -198,12 +213,17 @@ def run_backend(
|
||||
if web_dir.exists():
|
||||
(web_dir / constants.NOCOMPILE_FILE).touch()
|
||||
|
||||
if not frontend_present:
|
||||
notify_backend()
|
||||
|
||||
# Run the backend in development mode.
|
||||
backend_server_dev = config.backend_server_dev
|
||||
backend_server_dev.setup(host, port, loglevel, Env.DEV)
|
||||
try:
|
||||
backend_server_dev.setup(host, port, loglevel, Env.DEV)
|
||||
except ImportError:
|
||||
if frontend_present:
|
||||
failed_start_signal.set()
|
||||
barrier.wait() # for unlock frontend server
|
||||
return
|
||||
|
||||
notify_backend(not frontend_present)
|
||||
backend_server_dev.run_dev()
|
||||
|
||||
|
||||
@ -225,12 +245,17 @@ def run_backend_prod(
|
||||
|
||||
config = get_config()
|
||||
|
||||
if not frontend_present:
|
||||
notify_backend()
|
||||
|
||||
# Run the backend in production mode.
|
||||
backend_server_prod = config.backend_server_prod
|
||||
backend_server_prod.setup(host, port, loglevel, Env.PROD)
|
||||
try:
|
||||
backend_server_prod.setup(host, port, loglevel, Env.PROD)
|
||||
except ImportError:
|
||||
if frontend_present:
|
||||
failed_start_signal.set()
|
||||
barrier.wait() # for unlock frontend server
|
||||
return
|
||||
|
||||
notify_backend(not frontend_present)
|
||||
processes.new_process(
|
||||
backend_server_prod.run_prod(),
|
||||
run=True,
|
||||
|
Loading…
Reference in New Issue
Block a user