226 lines
6.8 KiB
Python
226 lines
6.8 KiB
Python
#!/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)
|
|
|