
    `gj                        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       j)                         dz  d	z  Zd
ZdZ ej0                         Z ej4                         j6                  ZddZddZddZddZ ddZ!d dZ"d!dZ#dd	 	 	 	 	 	 	 d"dZ$d#dZ%dddd	 	 	 	 	 	 	 d$dZ&d%dZ'd&dZ(y)'a  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unknownc                 t   t         j                  j                  dd       t        j                  t         d      } t        j
                  | _        | j                  d       | j                  d       | j                  d       | j                  d       | j                  d	       | j                  d
       | S )NT)parentsexist_ok   )timeoutzPRAGMA busy_timeout=5000zPRAGMA journal_mode=WALz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))EXECUTIONS_FILEparentmkdirsqlite3connectRowrow_factoryexecute)conns    B/root/.hermes/venv/lib/python3.12/site-packages/cron/executions.py_connectr      s       =???A6D{{DLL+,LL*+LL*+LL	  	LL	: 	LL	: K    c                     | t        |       S d S )N)dict)rows    r   _recordr#   >   s    491T1r   c                >    	 ddl m}  ||       S # t        $ r Y y w xY w)Nr   )get_process_start_time)gateway.statusr%   	Exception)pidr%   s     r   _process_start_timer)   B   s'    9%c** s    	c                    	 ddl m}  ||       sy	 || t        j                         k(  S t        |       }|d uxr ||k(  S # t        $ r Y yw xY w)Nr   )_pid_existsFT)r&   r+   r'   osgetpidr)   )r(   
started_atr+   currents       r   _owner_is_liver0   J   sf    .3   biik!!!#&G$87j#88  s   A 	AAc                \    t        dt        t                    }| j                  d|f       y )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 ?
           ))maxintMAX_TERMINAL_EXECUTIONSr   )r   limits     r   _prune_unlockedr6   W   s,    3./0ELL	
 
r   c                  t               j                         }t        j                         j                  }t        j                         }t        5  t               5 }|j                  d|t        |       t        |      t        |t        |      |f       |j                  d|f      j                         }ddd       ddd       t              S # 1 sw Y   xY w# 1 sw Y   t              S xY w)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hexr,   r-   _lockr   r   str_PROCESS_IDr)   fetchoner#   )job_idsourcer
   execution_idr(   r   r"   s          r   create_executionrE   c   s    
-
!
!
#C::<##L
))+C	 
 d: 3v;F[# %s,	
 ll1L?

(* 	  3<   3<s%   CAC6CC	CC0c                z   t               j                         }t        5  t               5 }|j	                  d|| f      }|j
                  dk7  r	 ddd       ddd       yt        |j	                  d| f      j                               cddd       cddd       S # 1 sw Y   nxY wddd       y# 1 sw Y   yxY w)z7Transition one claimed attempt to running exactly once.zcUPDATE executions SET status='running', started_at=?
               WHERE id=? AND status='claimed'   Nr8   )r9   r:   r>   r   r   rowcountr#   rA   )rD   r
   r   curs       r   mark_execution_runningrJ   w   s    
-
!
!
#C	 

 
dll2,

 <<1
 
 
 t||1L?

(*
 
 
 
 
 
 
s.   B1%BB1 )B		B1B%	!B11B:)errorc          	        t               j                         }|rdnd}|rdn|rt        |      nd}t        5  t	               5 }|j                  d|||| f      }|j                  dk7  r	 ddd       ddd       yt        |       t        |j                  d| f      j                               cddd       cddd       S # 1 sw Y   nxY wddd       y# 1 sw Y   yxY w)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')rG   r8   )
r9   r:   r?   r>   r   r   rH   r6   r#   rA   )rD   successrK   r
   statusdetailr   rI   s           r   finish_executionrP      s     -
!
!
#C#[FT3u:<MF	 
 dllAS&,/

 <<1   	t||1L?

(*      s/   C'C*C;4C/	CC	CC c            
        t               j                         } d}t        5  t               5 }|j	                  d      j                         }|D ]R  }|d   t        k(  rt        t        |d         |d         r,|j	                  d| d|d   f      }||j                  z  }T |rt        |       d	d	d	       d	d	d	       |S # 1 sw Y   xY w# 1 sw Y   |S xY w)
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)r9   r:   r>   r   r   fetchallr@   r0   r3   rH   r6   )r
   changedr   rowsr"   rI   s         r   recover_interrupted_executionsrX      s    
-
!
!
#CG	 "
 "d||8
 (* 	  	$C< K/c#e*os3G/HI,,EHTC s||#G	$ D!)" "* N+" " "* Ns#   CBC0CC	CC2   )rB   r5   before_claimed_atc           
     F   g }g }| +|j                  d       |j                  t        |              |+|j                  d       |j                  t        |             |rddj                  |      z   nd}|j                  t        dt	        t        |      d                   t        5  t               5 }|j                  d	|z   d
z   |      j                         }ddd       ddd       D cg c]  }t        |       c}S # 1 sw Y   *xY w# 1 sw Y   .xY wc c}w )zFReturn indexed, newest-first execution history with cursor pagination.Nzjob_id=?zclaimed_at < ?z WHERE z AND  rG   i  zSELECT * FROM executionsz* ORDER BY claimed_at DESC, id DESC LIMIT ?)appendr?   joinr2   minr3   r>   r   r   rU   r!   )	rB   r5   rZ   clausesparamswherer   rW   r"   s	            r   list_executionsrc      s   
 GFz"c&k"$'(c+,-18IW--bE
MM#aSZ-./	 
 d||&.:;
 (*	 	  "&&#DI&&    's*   +D6'DD1DD	DDc                .    t        | d      }|r|d   S d S )NrG   )rB   r5   r   )rc   )rB   rW   s     r   latest_executionre      s    &2D47$$r   c                   t         j                  |       D cg c]  }|st        |       }}|si S dj                  d |D              }t        5  t               5 }|j                  d| d|      j                         }ddd       ddd       D ci c]  }|d   t        |       c}S c c}w # 1 sw Y   3xY w# 1 sw Y   7xY wc c}w )z9Load latest execution for many jobs in one indexed query.,c              3      K   | ]  }d   yw)?N ).0_s     r   	<genexpr>z$latest_executions.<locals>.<genexpr>   s     /AC/s   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)NrB   )r!   fromkeysr?   r^   r>   r   r   rU   )job_idsrB   cleanplaceholdersr   rW   r"   s          r   latest_executionsrr      s    '+}}W'=HVS[HEH	88///L	 
 d||$$0> 2MP
 
 (* 	  155CM49$55 I    6s4   B.B.B?%B3B?C3B<	8B??C)returnsqlite3.Connection)r"   zOptional[sqlite3.Row]rs   Optional[Dict[str, Any]])r(   r3   rs   Optional[int])r(   r3   r.   rv   rs   bool)r   rt   rs   None)rB   r?   rC   r?   rs   zDict[str, Any])rD   r?   rs   ru   )rD   r?   rM   rw   rK   Optional[str]rs   ru   )rs   r3   )rB   ry   r5   r3   rZ   ry   rs   zList[Dict[str, Any]])rB   r?   rs   ru   )ro   z	List[str]rs   zDict[str, Dict[str, Any]]))__doc__
__future__r   jsonr,   r   	threadingr;   pathlibr   typingr   r   r   r   hermes_constantsr	   hermes_timer
   r9   resolver   r4   _TERMINAL_STATESRLockr>   r<   r=   r@   r   r#   r)   r0   r6   rE   rJ   rP   rX   rc   re   rr   rj   r   r   <module>r      s   #  	     , , , *!#++-6H 5 	djjlD2
9	(" AE#'0=*:  $"'+'',/'$' '0%
6r   