
    .cjX                     |   d Z ddlmZ ddlZddlZddlZddlZddlZddlm	Z	 ddl
mZmZmZmZ ddlmZ ddlmZ  e                                            dz  d	z  Zd
ZdZ ej                    Z ej                    j        Zd5dZd6dZd7dZd8dZ d9dZ!d:d!Z"d;d#Z#dd$d<d(Z$d=d)Z%dd*dd+d>d/Z&d?d0Z'd@d4Z(dS )Aa  Profile-local durable audit ledger for cron execution attempts.

The ledger records what is known about each attempt; it is not a retry queue.
Interrupted attempts become ``unknown`` only after their exact owner process is
proved gone. Terminal states are immutable.
    )annotationsN)Path)AnyDictListOptional)get_hermes_home)nowcronzexecutions.dbi  )	completedfailedunknownreturnsqlite3.Connectionc                    ddl m}  t          j                            dd           t          j        t          d          }t
          j        |_        |	                    d            | |d	           |	                    d
           |	                    d           |	                    d           |	                    d           |S )Nr   )apply_wal_with_fallbackT)parentsexist_ok   )timeoutzPRAGMA busy_timeout=5000zcron/executions.db)db_labelzPRAGMA synchronous=FULLa  CREATE TABLE IF NOT EXISTS executions (
             id TEXT PRIMARY KEY,
             job_id TEXT NOT NULL,
             source TEXT NOT NULL,
             process_id TEXT NOT NULL,
             pid INTEGER NOT NULL,
             process_started_at INTEGER,
             status TEXT NOT NULL CHECK(status IN
               ('claimed','running','completed','failed','unknown')),
             claimed_at TEXT NOT NULL,
             started_at TEXT,
             finished_at TEXT,
             error TEXT
           )zeCREATE INDEX IF NOT EXISTS idx_executions_job_claimed ON executions(job_id, claimed_at DESC, id DESC)zhCREATE INDEX IF NOT EXISTS idx_executions_status_claimed ON executions(status, claimed_at DESC, id DESC))
hermes_stater   EXECUTIONS_FILEparentmkdirsqlite3connectRowrow_factoryexecute)r   conns     1/home/ice/.hermes/hermes-agent/cron/executions.py_connectr#      s    444444   ===??A666D{DLL+,,,D+?@@@@LL*+++LL	    	LL	:   	LL	:   K    rowOptional[sqlite3.Row]Optional[Dict[str, Any]]c                (    | t          |           nd S )Ndict)r%   s    r"   _recordr+   @   s    4999T1r$   pidintOptional[int]c                H    	 ddl m}  ||           S # t          $ r Y d S w xY w)Nr   )get_process_start_time)gateway.statusr0   	Exception)r,   r0   s     r"   _process_start_timer3   D   sL    999999%%c***   tts    
!!
started_atboolc                    	 ddl m}  ||           sdS n# t          $ r Y dS w xY w|| t          j                    k    S t          |           }|d uo||k    S )Nr   )_pid_existsFT)r1   r7   r2   osgetpidr3   )r,   r4   r7   currents       r"   _owner_is_liver;   L   s    ......{3 	5	   ttbikk!!!#&&G$87j#88s    
$$r!   Nonec                x    t          dt          t                              }|                     d|f           d S )Nr   zDELETE FROM executions WHERE id IN (
             SELECT id FROM executions
             WHERE status IN ('completed','failed','unknown')
             ORDER BY claimed_at DESC, id DESC LIMIT -1 OFFSET ?
           ))maxr-   MAX_TERMINAL_EXECUTIONSr    )r!   limits     r"   _prune_unlockedrA   Y   sF    3.//00ELL	
 
    r$   job_idstrsourceDict[str, Any]c               $   t                                                      }t          j                    j        }t          j                    }t          5  t                      5 }|	                    d|t          |           t          |          t          |t          |          |f           |	                    d|f                                          }ddd           n# 1 swxY w Y   ddd           n# 1 swxY w Y   t          |          S )z<Persist a claimed attempt before executor/provider dispatch.zINSERT INTO executions
               (id, job_id, source, process_id, pid, process_started_at,
                status, claimed_at)
               VALUES (?, ?, ?, ?, ?, ?, 'claimed', ?)#SELECT * FROM executions WHERE id=?N)_hermes_now	isoformatuuiduuid4hexr8   r9   _lockr#   r    rC   _PROCESS_IDr3   fetchoner+   )rB   rD   r
   execution_idr,   r!   r%   s          r"   create_executionrQ   e   sb   
--
!
!
#
#C:<<#L
)++C	  

 d: 3v;;F[# %%s,	
 	
 	
 ll1L?
 

(** 	                              3<<s7   C8"A3C!C8!C%	%C8(C%	)C88C<?C<rP   c                   t                                                      }t          5  t                      5 }|                    d|| f          }|j        dk    r	 ddd           ddd           dS t          |                    d| f                                                    cddd           cddd           S # 1 swxY w Y   ddd           dS # 1 swxY w Y   dS )z7Transition one claimed attempt to running exactly once.zcUPDATE executions SET status='running', started_at=?
               WHERE id=? AND status='claimed'   NrG   )rH   rI   rM   r#   r    rowcountr+   rO   )rP   r
   r!   curs       r"   mark_execution_runningrV   y   s   
--
!
!
#
#C	 
 


 
dll2,
 

 <1
 
 
 
 
 
 
 
 
 
 
 
 
 
 t||1L?
 

(** 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
s@   C%CC45C)CC	C	C	
CC!C)errorsuccessrW   Optional[str]c          	     *   t                                                      }|rdnd}|rdn|rt          |          nd}t          5  t	                      5 }|                    d|||| f          }|j        dk    r	 ddd           ddd           dS t          |           t          |                    d| f          	                                          cddd           cddd           S # 1 swxY w Y   ddd           dS # 1 swxY w Y   dS )zDWrite a terminal result once; terminal attempts cannot be rewritten.r   r   Nzunknown failureztUPDATE executions SET status=?, finished_at=?, error=?
               WHERE id=? AND status IN ('claimed','running')rS   rG   )
rH   rI   rC   rM   r#   r    rT   rA   r+   rO   )rP   rX   rW   r
   statusdetailr!   rU   s           r"   finish_executionr]      s    --
!
!
#
#C#1[[FNTT#M3u:::<MF	  

 dllAS&,/
 

 <1              	t||1L?
 

(**                                         sC   D'C0;DAC0D0C4	4D7C4	8DDDc            
        t                                                      } d}t          5  t                      5 }|                    d                                          }|D ]g}|d         t          k    rt          t          |d                   |d                   r>|                    d| d|d         f          }||j	        z  }h|rt          |           d	d	d	           n# 1 swxY w Y   d	d	d	           n# 1 swxY w Y   |S )
zDMark provably abandoned attempts unknown without scheduling retries.r   zsSELECT id, process_id, pid, process_started_at FROM executions
               WHERE status IN ('claimed','running')
process_idr,   process_started_atzUPDATE executions SET status='unknown', finished_at=?, error=?
                   WHERE id=? AND status IN ('claimed','running')z}Scheduler restarted after this execution's owner exited before a durable terminal state; whether side effects ran is unknown.idN)rH   rI   rM   r#   r    fetchallrN   r;   r-   rT   rA   )r
   changedr!   rowsr%   rU   s         r"   recover_interrupted_executionsre      s   
--
!
!
#
#CG	 " "

 "d||8
 
 (** 	  	$ 	$C< K//c#e*oos3G/HII ,,EHT C s|#GG 	"D!!!)" " " " " " " " " " " " " " " " " " " " " " " " " " " " " "* Ns5   C?B#C(C?(C,	,C?/C,	0C??DD2   )rB   r@   before_claimed_atr@   rg   List[Dict[str, Any]]c           
        g }g }| 7|                     d           |                     t          |                      |7|                     d           |                     t          |                     |rdd                    |          z   nd}|                     t          dt	          t          |          d                               t          5  t                      5 }|                    d	|z   d
z   |          	                                }ddd           n# 1 swxY w Y   ddd           n# 1 swxY w Y   d |D             S )zFReturn indexed, newest-first execution history with cursor pagination.Nzjob_id=?zclaimed_at < ?z WHERE z AND  rS   i  zSELECT * FROM executionsz* ORDER BY claimed_at DESC, id DESC LIMIT ?c                ,    g | ]}t          |          S  r)   .0r%   s     r"   
<listcomp>z#list_executions.<locals>.<listcomp>   s    &&&#DII&&&r$   )
appendrC   joinr>   minr-   rM   r#   r    rb   )rB   r@   rg   clausesparamswherer!   rd   s           r"   list_executionsrv      s   
 GFz"""c&kk"""$'(((c+,,---18@IW----bE
MM#aSZZ--..///	  

 d||&.:;
 
 (**	 	                              '&&&&&s6   D9'/D"D9"D&	&D9)D&	*D99D= D=c                <    t          | d          }|r|d         nd S )NrS   )rB   r@   r   )rv   )rB   rd   s     r"   latest_executionrx      s'    &222D$477$r$   job_ids	List[str]Dict[str, Dict[str, Any]]c                   d t                               |           D             }|si S d                    d |D                       }t          5  t	                      5 }|                    d| d|                                          }ddd           n# 1 swxY w Y   ddd           n# 1 swxY w Y   d |D             S )z9Load latest execution for many jobs in one indexed query.c                0    g | ]}|t          |          S rl   )rC   )rn   rB   s     r"   ro   z%latest_executions.<locals>.<listcomp>   s#    HHHVHS[[HHHr$   ,c              3     K   | ]}d V  dS )?Nrl   )rn   _s     r"   	<genexpr>z$latest_executions.<locals>.<genexpr>   s"      //AC//////r$   z@SELECT e.* FROM executions e
                WHERE e.job_id IN (z)
                  AND e.id=(SELECT e2.id FROM executions e2
                            WHERE e2.job_id=e.job_id
                            ORDER BY e2.claimed_at DESC, e2.id DESC LIMIT 1)Nc                :    i | ]}|d          t          |          S )rB   r)   rm   s     r"   
<dictcomp>z%latest_executions.<locals>.<dictcomp>   s$    555CM499555r$   )r*   fromkeysrq   rM   r#   r    rb   )ry   cleanplaceholdersr!   rd   s        r"   latest_executionsr      s[   HHt}}W'='=HHHE 	88///////L	  

 d||P$0P P P
 
 
 (** 	                              655555s6   B.-BB.B	B.B	B..B25B2)r   r   )r%   r&   r   r'   )r,   r-   r   r.   )r,   r-   r4   r.   r   r5   )r!   r   r   r<   )rB   rC   rD   rC   r   rE   )rP   rC   r   r'   )rP   rC   rX   r5   rW   rY   r   r'   )r   r-   )rB   rY   r@   r-   rg   rY   r   rh   )rB   rC   r   r'   )ry   rz   r   r{   ))__doc__
__future__r   jsonr8   r   	threadingrJ   pathlibr   typingr   r   r   r   hermes_constantsr	   hermes_timer
   rH   resolver   r?   _TERMINAL_STATESRLockrM   rK   rL   rN   r#   r+   r3   r;   rA   rQ   rV   r]   re   rv   rx   r   rl   r$   r"   <module>r      s    # " " " " "  				             , , , , , , , , , , , , , , , , , , * * * * * *!/##++--6H 5 	djll! ! ! !H2 2 2 2   
9 
9 
9 
9	 	 	 	   (   " AE     *   :  $"'+' ' ' ' ' '0% % % %
6 6 6 6 6 6r$   