import os import signal import subprocess import sys import time from pathlib import Path import psutil def kill_flask_servers(): """ Kill all Python processes running main.py (Flask servers) Uses psutil to find and kill processes more reliably than just using command line """ killed_pids = [] for proc in psutil.process_iter(["pid", "name", "cmdline"]): try: cmdline = proc.info["cmdline"] if ( cmdline and "python" in proc.info["name"].lower() and any( "local_deep_research.web.app" in arg for arg in cmdline if arg ) ): pid = proc.info["pid"] print(f"Found Flask server process {pid}, killing...") # Windows requires SIGTERM os.kill(pid, signal.SIGTERM) killed_pids.append(pid) except ( psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess, ): pass if killed_pids: print( f"Killed Flask server processes with PIDs: {', '.join(map(str, killed_pids))}" ) else: print("No Flask server processes found.") # Give processes time to die time.sleep(1) # Verify all are dead for pid in killed_pids: if psutil.pid_exists(pid): print(f"Warning: Process {pid} still exists after kill signal.") else: print(f"Confirmed process {pid} was terminated.") return killed_pids def check_flask_servers(): """Check if any Flask servers are running and return their PIDs.""" running_servers = [] for proc in psutil.process_iter(["pid", "name", "cmdline"]): try: cmdline = proc.info["cmdline"] if ( cmdline and "python" in proc.info["name"].lower() and any( "local_deep_research.web.app" in arg for arg in cmdline if arg ) ): pid = proc.info["pid"] running_servers.append(pid) except ( psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess, ): pass return running_servers def start_flask_server(port=5000): """Start a Flask server in the background.""" print(f"Starting Flask server on port {port}...") # Get the virtual environment Python executable # Try multiple common venv locations venv_paths = [ Path("venv_dev") / "bin" / "python", # Linux/Mac Path("venv") / "bin" / "python", # Linux/Mac Path(".venv") / "Scripts" / "python.exe", # Windows Path("venv_dev") / "Scripts" / "python.exe", # Windows Path("venv") / "Scripts" / "python.exe", # Windows ] venv_path = None for path in venv_paths: if path.exists(): venv_path = str(path) break if not venv_path: print( "Error: Could not find Python executable in any common venv location" ) return None try: # First, check if port is already in use import socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) result = sock.connect_ex(("127.0.0.1", port)) sock.close() if result == 0: print(f"Error: Port {port} is already in use") return None # Start the Flask server directly without background flags # to better catch any startup errors process = subprocess.Popen( [ venv_path, "-m", "local_deep_research.web.app", "--port", str(port), ], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, # Use text mode for easier output reading ) # Wait a moment to ensure the server has time to start time.sleep(3) # Check if the process is still running if process.poll() is None: print(f"Flask server started on port {port} with PID {process.pid}") # Try to read initial output to see if there are errors stdout_data, stderr_data = "", "" try: # Read with timeout to avoid blocking import select if os.name == "nt": # Windows # Windows doesn't support select on pipes, use non-blocking mode import msvcrt if ( process.stdout and msvcrt.get_osfhandle(process.stdout.fileno()) != -1 ): stdout_data = process.stdout.read(1024) or "" if ( process.stderr and msvcrt.get_osfhandle(process.stderr.fileno()) != -1 ): stderr_data = process.stderr.read(1024) or "" else: # Unix if ( process.stdout and select.select([process.stdout], [], [], 0.5)[0] ): stdout_data = process.stdout.read(1024) or "" if ( process.stderr and select.select([process.stderr], [], [], 0.5)[0] ): stderr_data = process.stderr.read(1024) or "" except Exception as e: print(f"Warning: Could not read process output: {e}") # Log any output for debugging if stdout_data: print(f"Server stdout: {stdout_data.strip()}") if stderr_data: print(f"Server stderr: {stderr_data.strip()}") # Test if the server is actually responding try: import urllib.request with urllib.request.urlopen( f"http://localhost:{port}/", timeout=2 ) as response: if response.status == 200: print( f"Server is responsive at http://localhost:{port}/" ) else: print( f"Warning: Server responded with status {response.status}" ) except Exception as e: print(f"Warning: Could not connect to server: {e}") print( "The process is running but the server may not be responding to requests" ) return process.pid else: stdout, stderr = process.communicate() print( f"Error starting Flask server. Server process exited with code {process.returncode}" ) if stdout: print(f"Server stdout: {stdout.strip()}") if stderr: print(f"Server stderr: {stderr.strip()}") return None except Exception as e: print(f"Error starting Flask server: {e!s}") return None def start_flask_server_windows(port=5000): """Start a Flask server using Windows 'start' command which is more reliable for Windows environments.""" print( f"Starting Flask server on port {port} using Windows 'start' command..." ) # Get the virtual environment Python executable # Try multiple common venv locations venv_paths = [ Path("venv_dev") / "Scripts" / "python.exe", # Windows Path("venv") / "Scripts" / "python.exe", # Windows Path(".venv") / "Scripts" / "python.exe", # Windows ] venv_path = None for path in venv_paths: if path.exists(): venv_path = str(path) break if not venv_path: print( "Error: Could not find Python executable in any common venv location" ) return None try: # Use Windows 'start' command to launch in a new window # This is more reliable on Windows for Flask apps cmd = f'start "Flask Server" /MIN "{venv_path}" -m local_deep_research.web.app --port {port}' subprocess.run(cmd, shell=True, check=True) print(f"Flask server starting on port {port}") print( "Note: The process is running in a minimized window. Close that window to stop the server." ) # Wait a moment to ensure the server has time to start time.sleep(3) # We can't get the PID easily with this method, but return True to indicate success return True except Exception as e: print(f"Error starting Flask server: {e!s}") return None def restart_server(port=5000): """Kill all Flask servers and start a new one.""" kill_flask_servers() print("All Flask server processes terminated.") pid = start_flask_server(port) if pid: print(f"New Flask server started on port {port} with PID {pid}") return True else: print("Failed to start new Flask server") return False def show_status(): """Show status of running Flask servers.""" running_servers = check_flask_servers() if running_servers: print(f"Found {len(running_servers)} running Flask server(s):") for pid in running_servers: try: proc = psutil.Process(pid) cmdline = proc.cmdline() port = None # Try to extract the port number for i, arg in enumerate(cmdline): if arg == "--port" and i + 1 < len(cmdline): port = cmdline[i + 1] if port: print(f" - PID {pid}: Running on port {port}") else: print(f" - PID {pid}: Running (port unknown)") except (psutil.NoSuchProcess, psutil.AccessDenied): print(f" - PID {pid}: [Process information unavailable]") else: print("No Flask servers currently running.") return len(running_servers) > 0 if __name__ == "__main__": if len(sys.argv) > 1: if sys.argv[1] == "restart": kill_flask_servers() print("All Flask server processes terminated.") if os.name == "nt": # Windows start_flask_server_windows() else: start_flask_server() elif sys.argv[1] == "start": if os.name == "nt": # Windows start_flask_server_windows() else: start_flask_server() elif sys.argv[1] == "status": show_status() else: print( "Unknown command. Usage: python kill_servers.py [restart|start|status]" ) else: kill_flask_servers()