Spaces:
Build error
Build error
| """ | |
| Shared utilities for starting the FastAPI server in development and production modes. | |
| This module provides common functionality for server startup scripts to avoid code duplication. | |
| """ | |
| import os | |
| import socket | |
| import subprocess | |
| import sys | |
| from pathlib import Path | |
| from typing import Optional, Tuple | |
| def load_environment(project_root: Path) -> None: | |
| """ | |
| Load environment variables from .env file if it exists. | |
| Args: | |
| project_root: Root directory of the project | |
| """ | |
| env_file = project_root / '.env' | |
| if env_file.exists(): | |
| from dotenv import load_dotenv | |
| load_dotenv(env_file) | |
| def check_port_in_use(port: int = 8000) -> bool: | |
| """ | |
| Check if the specified port is already in use. | |
| Args: | |
| port: Port number to check | |
| Returns: | |
| True if port is in use, False otherwise | |
| """ | |
| with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: | |
| return s.connect_ex(('localhost', port)) == 0 | |
| def get_pid_on_port(port: int = 8000) -> Optional[int]: | |
| """ | |
| Get the PID of the process using the specified port. | |
| Args: | |
| port: Port number to check | |
| Returns: | |
| PID if found, None otherwise | |
| """ | |
| try: | |
| if sys.platform == 'win32': | |
| # Windows: use netstat | |
| result = subprocess.run( | |
| ['netstat', '-ano'], | |
| capture_output=True, | |
| text=True, | |
| check=False | |
| ) | |
| for line in result.stdout.split('\n'): | |
| if f':{port}' in line and 'LISTENING' in line: | |
| parts = line.split() | |
| if parts: | |
| return int(parts[-1]) | |
| else: | |
| # Unix/Linux/macOS: use lsof | |
| result = subprocess.run( | |
| ['lsof', '-ti', f':{port}'], | |
| capture_output=True, | |
| text=True, | |
| check=False | |
| ) | |
| if result.stdout.strip(): | |
| return int(result.stdout.strip().split('\n')[0]) | |
| except (subprocess.SubprocessError, ValueError): | |
| pass | |
| return None | |
| def kill_server_on_port(port: int = 8000) -> bool: | |
| """ | |
| Kill the server process running on the specified port. | |
| Args: | |
| port: Port number to check | |
| Returns: | |
| True if a process was killed, False otherwise | |
| """ | |
| pid = get_pid_on_port(port) | |
| if pid: | |
| try: | |
| print(f"Killing server process on port {port} (PID: {pid})...") | |
| if sys.platform == 'win32': | |
| # Windows: use taskkill | |
| subprocess.run(['taskkill', '/F', '/PID', str(pid)], check=True) | |
| else: | |
| # Unix/Linux/macOS: use kill | |
| subprocess.run(['kill', str(pid)], check=True) | |
| # Wait a moment for the process to terminate | |
| import time | |
| time.sleep(1) | |
| return True | |
| except subprocess.SubprocessError as e: | |
| print(f"Error killing process: {e}", file=sys.stderr) | |
| return False | |
| return False | |
| def get_host_and_port() -> Tuple[str, int]: | |
| """ | |
| Determine host and port from environment variables or CLI arguments. | |
| Priority: env vars > CLI arguments > defaults | |
| Returns: | |
| Tuple of (host, port) | |
| """ | |
| host = os.environ.get('HOST') or (sys.argv[1] if len(sys.argv) > 1 else "localhost") | |
| port = int(os.environ.get('PORT') or (sys.argv[2] if len(sys.argv) > 2 else 8000)) | |
| return host, port | |
| def setup_log_directory(project_root: Path) -> Path: | |
| """ | |
| Create log directory and return path to server log file. | |
| This returns the path for uvicorn/server logs (access logs, startup messages). | |
| Application logs are written separately by the Python logging FileHandler. | |
| The log directory can be configured via the LOG_DIR environment variable. | |
| Args: | |
| project_root: Root directory of the project | |
| Returns: | |
| Path to the server log file | |
| """ | |
| log_dir_env = os.environ.get("LOG_DIR") | |
| if log_dir_env: | |
| log_dir = Path(log_dir_env) | |
| else: | |
| log_dir = project_root / "log" | |
| log_dir.mkdir(parents=True, exist_ok=True) | |
| return log_dir / "server.log" | |
| def print_server_running_message(host: str, port: int, pid: Optional[int] = None) -> None: | |
| """ | |
| Print message when server is already running. | |
| Args: | |
| host: Server host | |
| port: Server port | |
| pid: Process ID if available | |
| """ | |
| print() | |
| print("=" * 86) | |
| print(f"FastAPI server is already running on port {port}" + (f" (PID: {pid})" if pid else "")) | |
| print(f"The server automatically reloads on file changes.") | |
| print(f"To restart, kill the process and run this command again.") | |
| if pid: | |
| print(f" kill {pid}") | |
| print(f"Open http://{host}:{port}?dev to access app in development mode.") | |
| print(f"API docs available at: http://{host}:{port}/docs") | |
| print("=" * 86) | |
| print() | |
| def print_server_starting_message(host: str, port: int, log_file: Path, mode: str = "development", auto_reload: bool = True) -> None: | |
| """ | |
| Print message when starting the server. | |
| Args: | |
| host: Server host | |
| port: Server port | |
| log_file: Path to log file | |
| mode: Server mode ("development" or "production") | |
| auto_reload: Whether auto-reload is enabled | |
| """ | |
| print() | |
| print("=" * 86) | |
| print(f"Starting FastAPI {mode} server.") | |
| print(f"Server output being logged to: {log_file}") | |
| if mode == "development": | |
| if auto_reload: | |
| print(f"The server will automatically reload when files change.") | |
| else: | |
| print(f"Auto-reload is disabled. Use 'bin/start-dev --restart' to restart after changes.") | |
| print(f"Open http://{host}:{port}?dev to access app in development mode.") | |
| else: | |
| print(f"Open http://{host}:{port} to access the application.") | |
| print(f"API docs available at: http://{host}:{port}/docs") | |
| print("=" * 86) | |
| print() | |