Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 3 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions reflex/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,13 +161,13 @@ class Config:
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}"
Expand Down
2 changes: 2 additions & 0 deletions reflex/constants/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
from .config import (
ALEMBIC_CONFIG,
Config,
DefaultPorts,
Expiration,
GitIgnore,
RequirementsTxt,
Expand Down Expand Up @@ -72,6 +73,7 @@
ComponentName,
CustomComponents,
DefaultPage,
DefaultPorts,
Dirs,
Endpoint,
Env,
Expand Down
7 changes: 7 additions & 0 deletions reflex/constants/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
14 changes: 9 additions & 5 deletions reflex/reflex.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
27 changes: 27 additions & 0 deletions reflex/utils/processes.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to handle the case where they specifically, but it seems hard to do with how we're handling the default values now. We can come back to this if needed.

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.

Expand Down
Loading