""" Manual Job Monitor - Monitor job execution in real-time Usage: python monitor_job.py python monitor_job.py --job-id """ import sys import time import argparse from pathlib import Path from core.database import SchedulerDatabase from core.config import SchedulerConfig def monitor_by_execution_id(execution_id: int): """Monitor a specific job execution by execution ID""" config = SchedulerConfig() db = SchedulerDatabase(config.database_path) # Get execution details execution = db.get_execution(execution_id) if not execution: print(f"ERROR: Execution ID {execution_id} not found") return 1 # Get job details to get job name job = db.get_job(execution['job_id']) job_name = job['name'] if job else f"Job ID {execution['job_id']}" log_file = execution['log_file'] status = execution['status'] print("=" * 80) print(f"JOB MONITOR - Execution ID: {execution_id}") print("=" * 80) print(f"Job Name: {job_name}") print(f"Status: {status}") print(f"Start Time: {execution['start_time']}") print(f"Log File: {log_file}") print("=" * 80) print() if status in ['completed', 'failed', 'timeout']: print(f"Job already finished with status: {status}") print(f"Exit Code: {execution['exit_code']}") print(f"Duration: {execution['duration']} seconds") print() print("Showing complete log file:") print("=" * 80) print() # Show complete log if Path(log_file).exists(): with open(log_file, 'r', encoding='utf-8', errors='replace') as f: print(f.read()) else: print(f"ERROR: Log file not found: {log_file}") return 0 # Job is running - monitor in real-time print(f"Job is RUNNING - monitoring log file in real-time...") print(f"Press Ctrl+C to stop monitoring (job will continue running)") print("=" * 80) print() if not Path(log_file).exists(): print("Waiting for log file to be created...") max_wait = 30 waited = 0 while not Path(log_file).exists() and waited < max_wait: time.sleep(0.5) waited += 0.5 if not Path(log_file).exists(): print(f"ERROR: Log file not created after {max_wait} seconds") return 1 # Monitor log file with open(log_file, 'r', encoding='utf-8', errors='replace') as f: # Read existing content content = f.read() if content: print(content, end='') last_position = f.tell() no_change_count = 0 try: while True: # Check execution status execution = db.get_execution(execution_id) if execution['status'] in ['completed', 'failed', 'timeout']: # Read any remaining content f.seek(last_position) remaining = f.read() if remaining: print(remaining, end='', flush=True) print() print("=" * 80) print(f"JOB FINISHED - Status: {execution['status']}") print(f"Exit Code: {execution['exit_code']}") print(f"Duration: {execution['duration']} seconds") print("=" * 80) break # Read new content f.seek(last_position) new_content = f.read() if new_content: print(new_content, end='', flush=True) last_position = f.tell() no_change_count = 0 else: no_change_count += 1 # If no changes for 5 minutes, check if job is still alive if no_change_count >= 3000: # 5 minutes at 0.1s intervals print("\n[No new output for 5 minutes - job may be stuck]") no_change_count = 0 time.sleep(0.1) except KeyboardInterrupt: print("\n\n" + "=" * 80) print("MONITORING STOPPED BY USER") print(f"Job is still running (Execution ID: {execution_id})") print("=" * 80) return 0 return 0 def monitor_latest_by_job_id(job_id: int): """Monitor the latest execution of a specific job""" config = SchedulerConfig() db = SchedulerDatabase(config.database_path) # Get latest execution for this job executions = db.get_job_executions(job_id, limit=1) if not executions: print(f"ERROR: No executions found for Job ID {job_id}") return 1 execution_id = executions[0]['id'] print(f"Monitoring latest execution (ID: {execution_id}) for Job ID {job_id}") print() return monitor_by_execution_id(execution_id) def main(): parser = argparse.ArgumentParser( description='Monitor job execution in real-time', formatter_class=argparse.RawDescriptionHelpFormatter, epilog=""" Examples: # Monitor a specific execution by ID python monitor_job.py 42 # Monitor the latest execution of a specific job python monitor_job.py --job-id 2 # Show help python monitor_job.py --help """ ) parser.add_argument('execution_id', type=int, nargs='?', help='Execution ID to monitor') parser.add_argument('--job-id', type=int, help='Monitor latest execution of this Job ID') args = parser.parse_args() if args.job_id: return monitor_latest_by_job_id(args.job_id) elif args.execution_id: return monitor_by_execution_id(args.execution_id) else: parser.print_help() return 1 if __name__ == '__main__': sys.exit(main())