diff --git a/reflex/config.py b/reflex/config.py index 52f589c8c..eb34f413a 100644 --- a/reflex/config.py +++ b/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}" diff --git a/reflex/constants/__init__.py b/reflex/constants/__init__.py index c45a7f55d..547de703e 100644 --- a/reflex/constants/__init__.py +++ b/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, diff --git a/reflex/constants/config.py b/reflex/constants/config.py index 298934202..707a484aa 100644 --- a/reflex/constants/config.py +++ b/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" diff --git a/reflex/reflex.py b/reflex/reflex.py index 010cceaeb..a9e164477 100644 --- a/reflex/reflex.py +++ b/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): diff --git a/reflex/utils/processes.py b/reflex/utils/processes.py index cadd87547..f0c006871 100644 --- a/reflex/utils/processes.py +++ b/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.