Pārlūkot izejas kodu

[REF-2956] Fail When Backend port or frontend port is explicitly provided and the port is in use (#3432)

Elijah Ahianyo 11 mēneši atpakaļ
vecāks
revīzija
44ad9a7311

+ 2 - 2
reflex/config.py

@@ -161,13 +161,13 @@ class Config(Base):
     loglevel: constants.LogLevel = constants.LogLevel.INFO
 
     # The port to run the frontend on. NOTE: When running in dev mode, the next available port will be used if this is taken.
-    frontend_port: int = 3000
+    frontend_port: int = constants.DefaultPorts.FRONTEND_PORT
 
     # The path to run the frontend on. For example, "/app" will run the frontend on http://localhost:3000/app
     frontend_path: str = ""
 
     # The port to run the backend on. NOTE: When running in dev mode, the next available port will be used if this is taken.
-    backend_port: int = 8000
+    backend_port: int = constants.DefaultPorts.BACKEND_PORT
 
     # The backend url the frontend will connect to. This must be updated if the backend is hosted elsewhere, or in production.
     api_url: str = f"http://localhost:{backend_port}"

+ 2 - 0
reflex/constants/__init__.py

@@ -36,6 +36,7 @@ from .compiler import (
 from .config import (
     ALEMBIC_CONFIG,
     Config,
+    DefaultPorts,
     Expiration,
     GitIgnore,
     RequirementsTxt,
@@ -72,6 +73,7 @@ __ALL__ = [
     ComponentName,
     CustomComponents,
     DefaultPage,
+    DefaultPorts,
     Dirs,
     Endpoint,
     Env,

+ 7 - 0
reflex/constants/config.py

@@ -50,5 +50,12 @@ class RequirementsTxt(SimpleNamespace):
     DEFAULTS_STUB = f"{Reflex.MODULE_NAME}=="
 
 
+class DefaultPorts(SimpleNamespace):
+    """Default port constants."""
+
+    FRONTEND_PORT = 3000
+    BACKEND_PORT = 8000
+
+
 # The deployment URL.
 PRODUCTION_BACKEND_URL = "https://{username}-{app_name}.api.pynecone.app"

+ 9 - 5
reflex/reflex.py

@@ -157,12 +157,16 @@ def _run(
     if prerequisites.needs_reinit(frontend=frontend):
         _init(name=config.app_name, loglevel=loglevel)
 
-    # Find the next available open port.
-    if frontend and processes.is_process_on_port(frontend_port):
-        frontend_port = processes.change_port(frontend_port, "frontend")
+    # Find the next available open port if applicable.
+    if frontend:
+        frontend_port = processes.handle_port(
+            "frontend", frontend_port, str(constants.DefaultPorts.FRONTEND_PORT)
+        )
 
-    if backend and processes.is_process_on_port(backend_port):
-        backend_port = processes.change_port(backend_port, "backend")
+    if backend:
+        backend_port = processes.handle_port(
+            "backend", backend_port, str(constants.DefaultPorts.BACKEND_PORT)
+        )
 
     # Apply the new ports to the config.
     if frontend_port != str(config.frontend_port):

+ 27 - 0
reflex/utils/processes.py

@@ -109,6 +109,33 @@ def change_port(port: str, _type: str) -> str:
     return new_port
 
 
+def handle_port(service_name: str, port: str, default_port: str) -> str:
+    """Change port if the specified port is in use and is not explicitly specified as a CLI arg or config arg.
+    otherwise tell the user the port is in use and exit the app.
+
+    We make an assumption that when port is the default port,then it hasnt been explicitly set since its not straightforward
+    to know whether a port was explicitly provided by the user unless its any other than the default.
+
+    Args:
+        service_name: The frontend or backend.
+        port: The provided port.
+        default_port: The default port number associated with the specified service.
+
+    Returns:
+        The port to run the service on.
+
+    Raises:
+        Exit:when the port is in use.
+    """
+    if is_process_on_port(port):
+        if int(port) == int(default_port):
+            return change_port(port, service_name)
+        else:
+            console.error(f"{service_name.capitalize()} port: {port} is already in use")
+            raise typer.Exit()
+    return port
+
+
 def new_process(args, run: bool = False, show_logs: bool = False, **kwargs):
     """Wrapper over subprocess.Popen to unify the launch of child processes.