Files
gogo2/scripts/kill_stale_processes.py
2025-06-26 17:51:48 +03:00

197 lines
7.0 KiB
Python

#!/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)