#!/usr/bin/env python3 """ Cross-platform script to kill stale Python dashboard processes. Works on Linux, macOS, and Windows. """ import os import sys import signal import psutil import time from pathlib import Path # Dashboard script names to look for DASHBOARD_SCRIPTS = [ 'main_dashboard.py', 'run_clean_dashboard.py', 'web/clean_dashboard.py', 'web/cob_realtime_dashboard.py', 'ANNOTATE/web/app.py', 'COBY/main.py', 'run_integrated_rl_cob_dashboard.py', 'run_realtime_rl_cob_trader.py', ] # Ports used by dashboards DASHBOARD_PORTS = [8050, 8051, 8052, 8080, 8081, 5001] def is_dashboard_process(proc): """Check if a process is a dashboard process""" try: # Get process info cmdline = proc.cmdline() if not cmdline: return False # Join command line for easier searching cmd_str = ' '.join(cmdline).lower() # Check if it's a Python process if 'python' not in cmd_str: return False # Check if it's running one of our dashboard scripts for script in DASHBOARD_SCRIPTS: script_lower = script.lower() if script_lower in cmd_str: return True # Check if it's using one of our dashboard ports try: connections = proc.connections() for conn in connections: if hasattr(conn, 'laddr') and conn.laddr: if conn.laddr.port in DASHBOARD_PORTS: return True except (psutil.AccessDenied, psutil.NoSuchProcess): pass return False except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): return False def kill_process(proc, force=False): """Kill a process gracefully or forcefully""" try: pid = proc.pid name = proc.name() if force: # Force kill if sys.platform == 'win32': proc.kill() else: os.kill(pid, signal.SIGKILL) print(f" Force killed PID {pid} ({name})") else: # Graceful termination if sys.platform == 'win32': proc.terminate() else: os.kill(pid, signal.SIGTERM) print(f" Terminated PID {pid} ({name})") return True except (psutil.NoSuchProcess, psutil.AccessDenied, ProcessLookupError) as e: print(f" Could not kill PID {proc.pid}: {e}") return False def find_processes_on_ports(): """Find processes listening on dashboard ports""" port_processes = [] for proc in psutil.process_iter(['pid', 'name']): try: connections = proc.connections() for conn in connections: if hasattr(conn, 'laddr') and conn.laddr: if conn.laddr.port in DASHBOARD_PORTS and conn.status == 'LISTEN': port_processes.append({ 'pid': proc.pid, 'name': proc.name(), 'port': conn.laddr.port }) except (psutil.AccessDenied, psutil.NoSuchProcess): pass return port_processes def main(): print("=" * 60) print("Killing Stale Dashboard Processes") print("=" * 60) # Find dashboard processes dashboard_procs = [] print("\nScanning for dashboard processes...") for proc in psutil.process_iter(['pid', 'name', 'cmdline']): if is_dashboard_process(proc): dashboard_procs.append(proc) if not dashboard_procs: print(" No dashboard processes found") else: print(f" Found {len(dashboard_procs)} dashboard process(es):") for proc in dashboard_procs: try: cmdline = ' '.join(proc.cmdline()) print(f" - PID {proc.pid}: {cmdline[:80]}{'...' if len(cmdline) > 80 else ''}") except (psutil.NoSuchProcess, psutil.AccessDenied): print(f" - PID {proc.pid}: (access denied)") # Find processes on dashboard ports print("\nChecking for processes on dashboard ports...") port_procs = find_processes_on_ports() if not port_procs: print(" No processes found on dashboard ports") else: print(f" Found {len(port_procs)} process(es) on dashboard ports:") for p in port_procs: print(f" - PID {p['pid']} ({p['name']}) on port {p['port']}") # Add to kill list if not already there try: proc = psutil.Process(p['pid']) if proc not in dashboard_procs: dashboard_procs.append(proc) except psutil.NoSuchProcess: pass # Kill all found processes if dashboard_procs: print("\nTerminating processes...") killed_count = 0 # First, try graceful termination for proc in dashboard_procs: if kill_process(proc, force=False): killed_count += 1 # Wait for processes to exit print("\nWaiting for processes to exit...") time.sleep(2) # Force kill any remaining processes remaining = [] for proc in dashboard_procs: try: if proc.is_running(): remaining.append(proc) except psutil.NoSuchProcess: pass if remaining: print(f"\nForce killing {len(remaining)} remaining process(es)...") for proc in remaining: kill_process(proc, force=True) print(f"\n✓ Killed {killed_count} dashboard process(es)") else: print("\n✓ No processes to kill") print("\nPort status:") for port in DASHBOARD_PORTS: port_free = True for proc in psutil.process_iter(): try: for conn in proc.connections(): if hasattr(conn, 'laddr') and conn.laddr: if conn.laddr.port == port and conn.status == 'LISTEN': print(f" Port {port}: IN USE by PID {proc.pid}") port_free = False break if not port_free: break except (psutil.AccessDenied, psutil.NoSuchProcess): pass if port_free: print(f" Port {port}: FREE") print("\n" + "=" * 60) print("Process cleanup completed") print("=" * 60) if __name__ == '__main__': try: main() except KeyboardInterrupt: print("\n\nInterrupted by user") sys.exit(1) except Exception as e: print(f"\nError: {e}") import traceback traceback.print_exc() sys.exit(1)