From b2c51b82a5b2659977f55b8f55aa0f08bb380ba2 Mon Sep 17 00:00:00 2001 From: Sidharth Anil <44941778+sid-38@users.noreply.github.com> Date: Wed, 3 Apr 2024 16:43:28 -0500 Subject: [PATCH] Windows uvicorn bug fix (#2954) --- reflex/reflex.py | 5 +++++ reflex/utils/exec.py | 17 ++++++++++++++++- reflex/utils/prerequisites.py | 5 ----- reflex/utils/processes.py | 7 ++++++- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/reflex/reflex.py b/reflex/reflex.py index f93481917..547bb9a25 100644 --- a/reflex/reflex.py +++ b/reflex/reflex.py @@ -234,6 +234,11 @@ def _run( # In dev mode, run the backend on the main thread. if backend and env == constants.Env.DEV: backend_cmd(backend_host, int(backend_port)) + # The windows uvicorn bug workaround + # https://github.com/reflex-dev/reflex/issues/2335 + if constants.IS_WINDOWS and exec.frontend_process: + # Sends SIGTERM in windows + exec.kill(exec.frontend_process.pid) @cli.command() diff --git a/reflex/utils/exec.py b/reflex/utils/exec.py index 44acdf3ee..c3f62c9b1 100644 --- a/reflex/utils/exec.py +++ b/reflex/utils/exec.py @@ -7,6 +7,7 @@ import json import os import platform import re +import subprocess import sys from pathlib import Path from urllib.parse import urljoin @@ -18,6 +19,9 @@ from reflex.config import get_config from reflex.utils import console, path_ops from reflex.utils.watch import AssetFolderWatch +# For uvicorn windows bug fix (#2335) +frontend_process = None + def start_watching_assets_folder(root): """Start watching assets folder. @@ -66,6 +70,9 @@ def kill(proc_pid: int): process.kill() +# run_process_and_launch_url is assumed to be used +# only to launch the frontend +# If this is not the case, might have to change the logic def run_process_and_launch_url(run_command: list[str]): """Run the process and launch the URL. @@ -81,9 +88,17 @@ def run_process_and_launch_url(run_command: list[str]): while True: if process is None: + kwargs = {} + if constants.IS_WINDOWS: + kwargs["creationflags"] = subprocess.CREATE_NEW_PROCESS_GROUP # type: ignore process = processes.new_process( - run_command, cwd=constants.Dirs.WEB, shell=constants.IS_WINDOWS + run_command, + cwd=constants.Dirs.WEB, + shell=constants.IS_WINDOWS, + **kwargs, ) + global frontend_process + frontend_process = process if process.stdout: for line in processes.stream_logs("Starting frontend", process): match = re.search(constants.Next.FRONTEND_LISTENING_REGEX, line) diff --git a/reflex/utils/prerequisites.py b/reflex/utils/prerequisites.py index 5f3b5a7ba..0502be609 100644 --- a/reflex/utils/prerequisites.py +++ b/reflex/utils/prerequisites.py @@ -834,11 +834,6 @@ def check_initialized(frontend: bool = True): console.warn( """Windows Subsystem for Linux (WSL) is recommended for improving initial install times.""" ) - if sys.version_info >= (3, 12): - console.warn( - "Python 3.12 on Windows has known issues with hot reload (reflex-dev/reflex#2335). " - "Python 3.11 is recommended with this release of Reflex." - ) def is_latest_template() -> bool: diff --git a/reflex/utils/processes.py b/reflex/utils/processes.py index 2f38a141e..12bedb67c 100644 --- a/reflex/utils/processes.py +++ b/reflex/utils/processes.py @@ -14,6 +14,7 @@ import psutil import typer from redis.exceptions import RedisError +from reflex import constants from reflex.utils import console, path_ops, prerequisites @@ -227,7 +228,11 @@ def stream_logs(message: str, process: subprocess.Popen, progress=None): yield line # Check if the process failed (not printing the logs for SIGINT). - if process.returncode not in [0, -2]: + + # Windows uvicorn bug + # https://github.com/reflex-dev/reflex/issues/2335 + accepted_return_codes = [0, -2, 15] if constants.IS_WINDOWS else [0, -2] + if process.returncode not in accepted_return_codes: console.error(f"{message} failed with exit code {process.returncode}") for line in logs: console.error(line, end="")