#!/usr/bin/env python3 """ Kill Stale Processes Script Safely terminates stale Python processes related to the trading dashboard with proper error handling and graceful termination. """ import os import sys import time import signal from pathlib import Path import threading # Global timeout flag timeout_reached = False def timeout_handler(): """Handler for overall script timeout""" global timeout_reached timeout_reached = True print("\n⚠️ WARNING: Script timeout reached (10s) - forcing exit") os._exit(0) # Force exit def kill_stale_processes(): """Kill stale trading dashboard processes safely""" global timeout_reached # Set up overall timeout (10 seconds) timer = threading.Timer(10.0, timeout_handler) timer.daemon = True timer.start() try: import psutil except ImportError: print("psutil not available - using fallback method") return kill_stale_fallback() current_pid = os.getpid() killed_processes = [] failed_processes = [] # Keywords to identify trading dashboard processes target_keywords = [ 'dashboard', 'scalping', 'trading', 'tensorboard', 'run_clean', 'run_main', 'gogo2', 'mexc' ] try: print("Scanning for stale processes...") # Get all Python processes with timeout python_processes = [] scan_start = time.time() for proc in psutil.process_iter(['pid', 'name', 'cmdline']): if timeout_reached or (time.time() - scan_start) > 3.0: # 3s max for scanning print("Process scanning timeout - proceeding with found processes") break try: if proc.info['pid'] == current_pid: continue name = proc.info['name'].lower() if 'python' in name or 'tensorboard' in name: cmdline_str = ' '.join(proc.info['cmdline']) if proc.info['cmdline'] else '' # Check if this is a target process if any(keyword in cmdline_str.lower() for keyword in target_keywords): python_processes.append({ 'proc': proc, 'pid': proc.info['pid'], 'name': proc.info['name'], 'cmdline': cmdline_str }) except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): continue if not python_processes: print("No stale processes found") timer.cancel() # Cancel the timeout return True print(f"Found {len(python_processes)} target processes to terminate:") for p in python_processes[:5]: # Show max 5 to save time print(f" - PID {p['pid']}: {p['name']} - {p['cmdline'][:80]}...") if len(python_processes) > 5: print(f" ... and {len(python_processes) - 5} more") # Graceful termination first (with reduced wait time) print("\nAttempting graceful termination...") termination_start = time.time() for p in python_processes: if timeout_reached or (time.time() - termination_start) > 2.0: print("Termination timeout - moving to force kill") break try: proc = p['proc'] if proc.is_running(): proc.terminate() print(f" Sent SIGTERM to PID {p['pid']}") except Exception as e: failed_processes.append(f"Failed to terminate PID {p['pid']}: {e}") # Wait for graceful shutdown (reduced from 2.0 to 1.0) time.sleep(1.0) # Force kill remaining processes print("\nChecking for remaining processes...") kill_start = time.time() for p in python_processes: if timeout_reached or (time.time() - kill_start) > 2.0: print("Force kill timeout - exiting") break try: proc = p['proc'] if proc.is_running(): print(f" Force killing PID {p['pid']} ({p['name']})") proc.kill() killed_processes.append(f"Force killed PID {p['pid']} ({p['name']})") else: killed_processes.append(f"Gracefully terminated PID {p['pid']} ({p['name']})") except (psutil.NoSuchProcess, psutil.AccessDenied): killed_processes.append(f"Process PID {p['pid']} already terminated") except Exception as e: failed_processes.append(f"Failed to kill PID {p['pid']}: {e}") # Results (quick summary) print(f"\n=== Quick Results ===") print(f"✓ Cleaned up {len(killed_processes)} processes") if failed_processes: print(f"✗ Failed: {len(failed_processes)} processes") timer.cancel() # Cancel the timeout if we finished early return len(failed_processes) == 0 except Exception as e: print(f"Error during process cleanup: {e}") timer.cancel() return False def kill_stale_fallback(): """Fallback method using basic OS commands""" print("Using fallback process killing method...") try: if os.name == 'nt': # Windows import subprocess # Kill Python processes with dashboard keywords (with timeout) result = subprocess.run([ 'taskkill', '/f', '/im', 'python.exe' ], capture_output=True, text=True, timeout=5.0) if result.returncode == 0: print("Windows: Killed all Python processes") else: print("Windows: No Python processes to kill or access denied") else: # Unix/Linux import subprocess # More targeted approach for Unix (with timeouts) subprocess.run(['pkill', '-f', 'dashboard'], capture_output=True, timeout=2.0) subprocess.run(['pkill', '-f', 'scalping'], capture_output=True, timeout=2.0) subprocess.run(['pkill', '-f', 'tensorboard'], capture_output=True, timeout=2.0) print("Unix: Killed dashboard-related processes") return True except subprocess.TimeoutExpired: print("Fallback method timed out") return False except Exception as e: print(f"Fallback method failed: {e}") return False if __name__ == "__main__": print("=" * 50) print("STALE PROCESS CLEANUP (10s timeout)") print("=" * 50) start_time = time.time() success = kill_stale_processes() elapsed = time.time() - start_time exit_code = 0 if success else 1 print(f"Completed in {elapsed:.1f}s") print("=" * 50) sys.exit(exit_code)