From 94b5f788f4124e416d96cc6fc01ec720d3391a35 Mon Sep 17 00:00:00 2001 From: "Ankush Pala ankush@lastmileai.dev" <> Date: Tue, 26 Dec 2023 16:45:36 -0500 Subject: [PATCH] [editor] WIP Functiionality to run server on multiple configs ## What WHen running the server, user should be able to open multiple configs. Under the hood this means spinning up another server in an unused port. Frontend already supports dynamic ports. ## Testplan 1. yarn build in aiconfig/python/src/aiconfig/editor/client 2. Open two aiconfigs with "prod" editor" | Getting Started | Chain Of Verification | |------------|-------------| | ![Screenshot 1](https://github.com/lastmile-ai/aiconfig/assets/141073967/d30c9366-49d7-4b6d-851c-e469d47c4063) | ![Screenshot 2](https://github.com/lastmile-ai/aiconfig/assets/141073967/74c53dcc-52b6-4b67-84e1-7c8900045d4a)| | ![Screenshot 3](https://github.com/lastmile-ai/aiconfig/assets/141073967/6e86aa4f-8d7d-4140-b3ad-b374a90ae276) | ![Screenshot 4](https://github.com/lastmile-ai/aiconfig/assets/141073967/204120fa-305d-44b0-be3c-de33c342aa3c)| --- python/src/aiconfig/scripts/aiconfig_cli.py | 26 +++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/python/src/aiconfig/scripts/aiconfig_cli.py b/python/src/aiconfig/scripts/aiconfig_cli.py index 1296f8564..ce7742c19 100644 --- a/python/src/aiconfig/scripts/aiconfig_cli.py +++ b/python/src/aiconfig/scripts/aiconfig_cli.py @@ -3,6 +3,7 @@ import signal import subprocess import sys +import socket import lastmile_utils.lib.core.api as core_utils import result @@ -64,8 +65,33 @@ def _sigint(procs: list[subprocess.Popen[bytes]]) -> Result[str, str]: p.send_signal(signal.SIGINT) return Ok("Sent SIGINT to frontend servers.") +def is_port_in_use(port: int) -> bool: + """ + Checks if a port is in use at localhost. + + Creates a temporary connection. + Context manager will automatically close the connection + """ + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + return s.connect_ex(('localhost', port)) == 0 + def _run_editor_servers(edit_config: EditServerConfig) -> Result[list[str], str]: + + port = edit_config.server_port + + while is_port_in_use(port): + LOGGER.warning(f"Port {port} is in use. Checking next port.") + port += 1 + + # Must reconstruct, EditServerConfig is an immutable type (frozen dataclass) + edit_config_dict = edit_config.model_dump() + edit_config_dict["server_port"] = port + edit_config = EditServerConfig(**edit_config_dict) + + LOGGER.warning(f"Using {port}.") + + # Check if server is already running LOGGER.info("Running editor servers") frontend_procs = _run_frontend_server_background() if edit_config.server_mode in [ServerMode.DEBUG_SERVERS] else Ok([]) match frontend_procs: