ub4i-hdZddlZddlZddlZddlZddlmZddlmZddlm Z m Z m Z GddZ y)zJob execution module for DaemonControl. This module provides the JobExecutor class that handles executing jobs as subprocesses with logging, timeout management, and execution tracking. N)datetime)Path)DictOptionalTupleceZdZdZdZdedefdZdededdfdZd e e de fd Z ded e de fd Z d e defdZde dede e dedeee e e ff dZdefdZdde eddfdZy) JobExecutorz6Execute jobs as subprocesses with logging and timeout.c<||_||_||_i|_y)zInitialize job executor. Args: db_manager: DatabaseManager instance config_manager: ConfigManager instance logger: Logger instance N)dbconfigloggeractive_executions)self db_managerconfig_managerr s daemon/job_executor.py__init__zJobExecutor.__init__s!$  !#jobreturnc^ |jj|dd}|jjd|dd|dt j |j ||fd }||j|<|j|S#t$r}|jjd |dd ||jj|dd }|jj|tjjt| |cYd}~Sd}~wwxYw)a Execute a job asynchronously. Args: job: Job dict from database with keys: id, name, job_type, executable_path, working_directory, timeout Returns: execution_id: Database ID of created execution record idqueuedstatusz Queuing job 'namez' (execution_id: )T)targetargsdaemonzFailed to execute job 'z': failed)end_time error_messageN)r create_executionr info threadingThread_run_job_threadrstart Exceptionerrorupdate_executionrnow isoformatstr)rr execution_idthreades r execute_jobzJobExecutor.execute_job s" 7733CIh3OL KK  F },=l^1M  %%++"C(F 4:D " "< 0 LLN  KK   7F }CsK L 7733CIh3OL GG $ $!113!!f %    sB B D,B D'!D,'D,r0Nc R |jj|d|jjd|d|d|j |j d}|j ||}|j|d}|j dxs|jj dd d }|j|||j d|\}}} |jj|||tjjt|| |d k(r|jjn|jj} | d |d|d|||j vr|j |=yy#t$rs} |jjd |d| |jj|dtjjt| Yd} ~ d} ~ wwxYw#||j vr|j |=wwxYw)zRun job in subprocess (called in separate thread). Args: execution_id: Database execution record ID job: Job dictionary with execution details runningrzStarting execution z: rworking_directorytimeoutr default_timeouti)r exit_coder" log_outputr#successz Execution z completed: status=z , exit_code=z failed with exception: r!)rr"r#N)r r,r r%_get_python_executableget_build_command_create_log_file_pathr _execute_subprocessrr-r.r/r+r*r) rr0r python_execmdlog_filer7r9r error_msg log_levelr2s rr(zJobExecutor._run_job_threadIs7 9 GG $ $\) $ D KK  2<.3v;-P Q44SWW=P5QRJ%%c:6C11#f+>Hggi(DKKOO+T-G ,0+C+CXsww':;W, (Ivy GG $ $#!113x=' % -3i,? ((T[[EVEVI \N+ i[: $t555**<86  KK   <.8PQRPST U GG $ $!113!!f %   t555**<86s+E*F HA)H;HHHH&r6c|rMt|dz dz dz }|jr)|jjd|t |St j jd}|rJt|dz dz }|jr)|jjd|t |S|jjdtjtjS)aDetect Python executable with venv support. Priority: 1. Check working_directory/venv/bin/python (Linux venv) 2. Check $VIRTUAL_ENV/bin/python (if env var set) 3. Fallback to sys.executable (system Python) Args: working_directory: Optional working directory path Returns: Full path to Python executable venvbinpythonzUsing venv Python: VIRTUAL_ENVzUsing VIRTUAL_ENV Python: zUsing system Python: ) rexistsr debugr/osenvironr=sys executable)rr6 venv_python venv_paths rr<z"JobExecutor._get_python_executables 01F:UBXMK!!# !!$7 }"EF;''JJNN=1 y/E1H{m"LM;'' 1#..1ABC~~rrAc|d}|d}|dk(r||g}n.|dk(r|d|g}n#|jjd|d||g}|jjdd j||S) zBuild subprocess command based on job type. Args: job: Job dictionary python_exe: Path to Python executable Returns: Command as list of strings job_typeexecutable_pathscript python_modulez-mzUnknown job_type 'z', treating as scriptzBuilt command:  )r warningrLjoin)rrrArTrUrBs rr>zJobExecutor._build_commandsz?/0 x /C  (t_5C KK  $XJ.CD /C OCHHSM?;< rjob_namec|jjdd}t|j}|j ddt j jd}||d|dz }|S)zCreate path for execution log file. Format: ~/.config/daemon-control/logs/executions/{job_name}_{timestamp}.log Args: job_name: Name of the job Returns: Path object for log file loggingexecution_log_dirT)parentsexist_okz %Y%m%d_%H%M%S_z.log)r r=r expandusermkdirrr-strftime)rr[log_dir log_dir_path timestamprCs rr?z!JobExecutor._create_log_file_pathst++//)-@AG}//1  4$7LLN++O< XJa {$"??rrBrC working_dirr7c t|d5}|jd|jd|jd|jddj|d|jd|xsdd|jd |d |jd tjj d|jd |j tj||tj|d } |j|}|dk(rdnd}|dk(rdnd|} |jd|jdtjj d|jd|d|jd|jd|jdddd fS#tj$r|jjd|d|j|jd}d}d|d} |jd|jd|d |jd!|jdYwxYw#1swYxYw#t $r=} |jj#d"|dd}d}d"t%| } Yd} ~ d} ~ wt&$rD} |jj#d#t%| d}d}d#t%| } Yd} ~ Gd} ~ wt($rA} |jj#d$t%| d}d}t%| } Yd} ~ d} ~ wwxYw)%afExecute subprocess with timeout and logging. Args: cmd: Command list log_file: Path to log file working_dir: Working directory (or None) timeout: Timeout in seconds Returns: Tuple of (exit_code, status, error_message) status: 'success', 'failed', or 'timeout' wzG====================================================================== z(=== DaemonControl Job Execution Log === z Command: rX zWorking Directory: Nonez Timeout: zs z Start Time: zH====================================================================== T)stdoutstderrcwdtextr7rr;r!Nz Exit code: zH ====================================================================== z End Time: z Exit Code: zStatus: zProcess timeout after zs, killing processr7zTimeout after z secondsz!!! TIMEOUT after z seconds !!! zProcess was killed. zExecutable not found: zPermission denied: zSubprocess execution failed: )openwriterZrr-r.flush subprocessPopenSTDOUTwaitupperTimeoutExpiredr rYkillFileNotFoundErrorr+r/PermissionErrorr*) rrBrCrhr7fprocessr9rrDr2s rr@zJobExecutor._execute_subprocesss&E h$2 -(CD()CHHSM?"56-k.CV-DBGH)G9C01,x||~'?'?'A&B"EF)* %**%,,# - ' W =I*3q.YhF(1Qk)rr?rr@rrrrr r s@ $' t' ' R>9C>9d>9t>9@ #B$CD:cd0Z, Z,Z,c] Z,  Z, sC#& ' Z,x+C+5HSM5T5rr ) rrMrvrOr&rpathlibrtypingrrrr rrrrs0   ((E5E5r