§
    øžyjc'  ã                  ó¨  — 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mZ ddl	m
Z
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d<d„Zd=d„Zed>d„¦   «         Zd?d„Z ddœd@d„Z!dAd „Z"dBd#„Z#d=d$„Z$dCd)„Z%dDd+„Z&ddd,œdEd/„Z'dFd0„Z(dd1dd2œdGd6„Z)dHd7„Z*dId;„Z+dS )Ja  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)Úcontextmanager)ÚAnyÚDictÚIteratorÚListÚOptional)Úget_hermes_home)ÚnowÚcronzexecutions.dbiè  )Ú	completedÚfailedÚunknownÚreturnúsqlite3.Connectionc                 óz   — t           j                             dd¬¦  «         t          j        t           d¬¦  «        S )NT)ÚparentsÚexist_oké   )Útimeout)ÚEXECUTIONS_FILEÚparentÚmkdirÚsqlite3Úconnect© ó    ú5/home/ragecks/.hermes/hermes-agent/cron/executions.pyÚ_connectr      s3   € ÝÔ× Ò ¨¸Ð Ñ=Ô=Ð=ÝŒ?�?°AÐ6Ñ6Ô6Ð6r   ÚconnÚNonec                ó   — ddl m} t          j        | _        |                      d¦  «          || d¬¦  «         |                      d¦  «         |                      d¦  «         |                      d¦  «         |                      d	¦  «         d S )
Nr   )Úapply_wal_with_fallbackz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#   r   ÚRowÚrow_factoryÚexecute)r    r#   s     r   Ú_initialize_schemar)       sº   € Ø4Ð4Ð4Ð4Ð4Ð4å”{€DÔØ‡L‚LÐ+Ñ,Ô,Ð,ØÐ˜DÐ+?Ð@Ñ@Ô@Ð@Ø‡L‚LÐ*Ñ+Ô+Ð+Ø‡L‚Lð	ñô ð ð  	‡L‚Lð	:ñô ð ð 	‡L‚Lð	:ñô ð ð ð r   úIterator[sqlite3.Connection]c               #  ó   K  — t           5  t          ¦   «         } 	 t          | ¦  «         | 5  | V — ddd¦  «         n# 1 swxY w Y   |                      ¦   «          n# |                      ¦   «          w xY w	 ddd¦  «         dS # 1 swxY w Y   dS )aö  Open a connection, commit/rollback on exit, always close.

    ``sqlite3.Connection.__enter__``/``__exit__`` only commit or roll back
    the transaction; it does not close the connection. Relying on that alone
    leaks a connection (and its WAL/SHM file descriptors) on every call,
    since closing then depends on the garbage collector. Schema init runs
    inside the ``try`` too, so a PRAGMA/DDL failure after a successful
    ``connect()`` still closes the connection instead of leaking it.
    N)Ú_lockr   r)   Úclose)r    s    r   Ú_transactionr.   A   s  è è € õ 
ð ð Ý‰zŒzˆð	Ý˜tÑ$Ô$Ð$Øð ð Ø�
�
�
ðð ð ñ ô ð ð ð ð ð ð øøøð ð ð ð ð �JŠJ‰LŒLˆLˆLøˆD�JŠJ‰LŒLˆLˆLøøøˆLðð ð ñ ô ð ð ð ð ð ð ð øøøð ð ð ð ð ð sH   ŠBšA«<°A¼A 	Á AÁA 	ÁAÁBÁA2Á2BÂBÂ
BÚrowúOptional[sqlite3.Row]úOptional[Dict[str, Any]]c                ó(   — | �t          | ¦  «        nd S )N©Údict)r/   s    r   Ú_recordr5   V   s   € Ø˜�4�‰9Œ9ˆ9¨TÐ1r   ©Údelivery_outcomeÚrecordr7   úOptional[str]c               óP   — 	 ddl m}  || |¬¦  «         dS # t          $ r Y dS w xY w)zFProject durable state to monitoring without affecting ledger behavior.r   )Úemit_execution_stater6   N)Úagent.monitoring.cron_healthr;   Ú	Exception)r8   r7   r;   s      r   Ú_emit_execution_stater>   Z   sX   € ðØEÐEÐEÐEÐEÐEàÐ˜VÐ6FÐGÑGÔGÐGÐGÐGøÝð ð ð Øˆˆðøøøs   ‚ —
%¤%Ú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.statusrC   r=   )r?   rC   s     r   Ú_process_start_timerE   f   sL   € ðØ9Ð9Ð9Ð9Ð9Ð9Ø%Ð% cÑ*Ô*Ð*øÝð ð ð Øˆtˆtðøøø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)rD   rI   r=   ÚosÚgetpidrE   )r?   rF   rI   Úcurrents       r   Ú_owner_is_liverM   n   s�   € ðØ.Ð.Ð.Ð.Ð.Ð.Øˆ{˜3ÑÔð 	Ø�5ð	øåð ð ð ØˆtˆtðøøøàÐØ•b”i‘k”kÒ!Ð!Ý! #Ñ&Ô&€GØ˜$ÐÐ8 7¨jÒ#8Ð8s   ‚ –
$£$c                óx   — t          dt          t          ¦  «        ¦  «        }|                      d|f¦  «         d S )Nr   z×DELETE 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_unlockedrR   {   sF   € Ý�•3Õ.Ñ/Ô/Ñ0Ô0€EØ‡L‚Lð	ð
 
ˆñô ð ð ð r   Újob_idÚstrÚsourceúDict[str, Any]c               ó  — t          ¦   «                              ¦   «         }t          j        ¦   «         j        }t          j        ¦   «         }t          ¦   «         5 }|                     d|t          | ¦  «        t          |¦  «        t          |t          |¦  «        |f¦  «         |                     d|f¦  «                             ¦   «         }ddd¦  «         n# 1 swxY w Y   t          |¦  «        }t          |¦  «         |S )z<Persist a claimed attempt before executor/provider dispatch.zºINSERT 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ÚhexrJ   rK   r.   r(   rT   Ú_PROCESS_IDrE   Úfetchoner5   r>   )rS   rU   r   Úexecution_idr?   r    r/   r8   s           r   Úcreate_executionra   ‡   s  € å
‰-Œ-×
!Ò
!Ñ
#Ô
#€CÝ”:‘<”<Ô#€LÝ
Œ)‰+Œ+€CÝ	‰Œð ˜4Ø�Šð:ð �3˜v™;œ;­¨F©¬µ[À#Ý  Ñ%Ô% sð,ñ	
ô 	
ð 	
ð �lŠlØ1°L°?ñ
ô 
ç
Š(‰*Œ*ð 	ðð ð ñ ô ð ð ð ð ð ð øøøð ð ð ð õ �S‰\Œ\€FÝ˜&Ñ!Ô!Ð!Ø€Ms   ÁA3CÃCÃ Cr`   c                ó~  — t          ¦   «                              ¦   «         }t          ¦   «         5 }|                     d|| f¦  «        }|j        dk    r	 ddd¦  «         dS t          |                     d| f¦  «                             ¦   «         ¦  «        }ddd¦  «         n# 1 swxY w Y   t          |¦  «         |S )z7Transition one claimed attempt to running exactly once.zcUPDATE executions SET status='running', started_at=?
               WHERE id=? AND status='claimed'é   NrX   )rY   rZ   r.   r(   Úrowcountr5   r_   r>   )r`   r   r    Úcurr8   s        r   Úmark_execution_runningrf   �   s  € å
‰-Œ-×
!Ò
!Ñ
#Ô
#€CÝ	‰Œð 
˜4Ø�lŠlð2à�,Ðñ
ô 
ˆð
 Œ<˜1ÒÐØð
ð 
ð 
ñ 
ô 
ð 
ð 
ð 
õ ˜ŸšØ1°L°?ñ
ô 
ç
Š(‰*Œ*ñô ˆð
ð 
ð 
ñ 
ô 
ð 
ð 
ð 
ð 
ð 
ð 
øøøð 
ð 
ð 
ð 
õ ˜&Ñ!Ô!Ð!Ø€Ms   ¯%B#Á!6B#Â#B'Â*B')Úerrorr7   Úsuccessrg   c               óÞ  — t          ¦   «                              ¦   «         }|rdnd}|rdn|rt          |¦  «        nd}t          ¦   «         5 }|                     d|||| f¦  «        }|j        dk    r	 ddd¦  «         dS t          |¦  «         t          |                     d| f¦  «                             ¦   «         ¦  «        }	ddd¦  «         n# 1 swxY w Y   t          |	|¬¦  «         |	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')rc   rX   r6   )
rY   rZ   rT   r.   r(   rd   rR   r5   r_   r>   )
r`   rh   rg   r7   r   ÚstatusÚdetailr    re   r8   s
             r   Úfinish_executionrl   ¯   sZ  € õ
 ‰-Œ-×
!Ò
!Ñ
#Ô
#€CØ#Ð1ˆ[ˆ[¨€FØÐNˆTˆT°Ð#M¥3 u¡:¤: :Ð<M€FÝ	‰Œð ˜4Ø�lŠlðAà�S˜& ,Ð/ñ
ô 
ˆð
 Œ<˜1ÒÐØðð ð ñ ô ð ð ð õ 	˜ÑÔÐÝ˜ŸšØ1°L°?ñ
ô 
ç
Š(‰*Œ*ñô ˆðð ð ñ ô ð ð ð ð ð ð øøøð ð ð ð õ ˜&Ð3CÐDÑDÔDÐDØ€Ms   Á'CÂ ACÃCÃCc            	     óº  — t          ¦   «                              ¦   «         } d}g }t          ¦   «         5 }|                     d¦  «                             ¦   «         }|D ]Á}|d         t
          k    rŒt          t          |d         ¦  «        |d         ¦  «        rŒ>|                     d| d|d         f¦  «        }||j        z  }|j        rSt          |                     d	|d         f¦  «         
                    ¦   «         ¦  «        }|�|                     |¦  «         ŒÂ|rt          |¦  «         d
d
d
¦  «         n# 1 swxY w Y   |D ]}t          |¦  «         Œ|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_atz€UPDATE 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.ÚidrX   N)rY   rZ   r.   r(   Úfetchallr^   rM   r@   rd   r5   r_   ÚappendrR   r>   )r   ÚchangedÚ	recoveredr    Úrowsr/   re   r8   s           r   Úrecover_interrupted_executionsrv   Ç   s¿  € å
‰-Œ-×
!Ò
!Ñ
#Ô
#€CØ€GØ&(€IÝ	‰Œð "˜4Ø�|Š|ð8ñ
ô 
÷ Š(‰*Œ*ð 	ð ð 	-ð 	-ˆCØ�<Ô ¥KÒ/Ð/ØÝ�c # e¤*™oœo¨sÐ3GÔ/HÑIÔIð ØØ—,’,ðEàðHà�T”ðñô ˆCð �s”|Ñ#ˆGØŒ|ð -Ý  §¢Ø9¸CÀ¼I¸<ñ"ô "ç’(‘*”*ñô �ð Ð%Ø×$Ò$ VÑ,Ô,Ð,øØð 	"Ý˜DÑ!Ô!Ð!ð5"ð "ð "ñ "ô "ð "ð "ð "ð "ð "ð "øøøð "ð "ð "ð "ð6 ð &ð &ˆÝ˜fÑ%Ô%Ð%Ð%Ø€Ns   ³C=D<Ä<E ÅE é2   )rS   rQ   Úbefore_claimed_atrQ   rx   úList[Dict[str, Any]]c           
     ób  — g }g }| �7|                      d¦  «         |                      t          | ¦  «        ¦  «         |�7|                      d¦  «         |                      t          |¦  «        ¦  «         |rdd                     |¦  «        z   nd}|                      t          dt	          t          |¦  «        d¦  «        ¦  «        ¦  «         t          ¦   «         5 }|                     d	|z   d
z   |¦  «                             ¦   «         }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 Ú rc   iô  zSELECT * FROM executionsz* ORDER BY claimed_at DESC, id DESC LIMIT ?c                ó,   — g | ]}t          |¦  «        ‘ŒS r   r3   ©Ú.0r/   s     r   ú
<listcomp>z#list_executions.<locals>.<listcomp>  s   € Ð&Ð&Ð&˜#�D�‰IŒIÐ&Ð&Ð&r   )	rr   rT   ÚjoinrO   Úminr@   r.   r(   rq   )rS   rQ   rx   ÚclausesÚparamsÚwherer    ru   s           r   Úlist_executionsr…   ì   sd  € ð
 €GØ€FØÐØ�Š�zÑ"Ô"Ð"Ø�Š•c˜&‘k”kÑ"Ô"Ð"ØÐ$Ø�ŠÐ'Ñ(Ô(Ð(Ø�Š•cÐ+Ñ,Ô,Ñ-Ô-Ð-Ø18Ð@ˆI˜Ÿš WÑ-Ô-Ñ-Ð-¸b€EØ
‡M‚M•#�a��S ™ZœZ¨Ñ-Ô-Ñ.Ô.Ñ/Ô/Ð/Ý	‰Œð ˜4Ø�|Š|Ø&¨Ñ.Ø:ñ;àñ
ô 
÷ Š(‰*Œ*ð	 	ðð ð ñ ô ð ð ð ð ð ð øøøð ð ð ð ð 'Ð& Ð&Ñ&Ô&Ð&s   Ã/DÄDÄ!Dc                ó<   — t          | d¬¦  «        }|r|d         nd S )Nrc   )rS   rQ   r   )r…   )rS   ru   s     r   Úlatest_executionr‡     s'   € Ý &°Ð2Ñ2Ô2€DØÐ$ˆ4�Œ7ˆ7 Ð$r   Újob_idsú	List[str]úDict[str, Dict[str, Any]]c                óL  — d„ t                                | ¦  «        D ¦   «         }|si S d                     d„ |D ¦   «         ¦  «        }t          ¦   «         5 }|                     d|› d�|¦  «                             ¦   «         }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 r   )rT   )r~   rS   s     r   r   z%latest_executions.<locals>.<listcomp>  s#   € ÐHÐHÐH˜VÀÐH�S�‰[Œ[ÐHÐHÐHr   Ú,c              3  ó   K  — | ]}d V — ŒdS )ú?Nr   )r~   Ú_s     r   ú	<genexpr>z$latest_executions.<locals>.<genexpr>  s"   è è € Ð/Ð/ A˜CÐ/Ð/Ð/Ð/Ð/Ð/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 )rS   r3   r}   s     r   ú
<dictcomp>z%latest_executions.<locals>.<dictcomp>  s$   € Ð5Ð5Ð5¨ˆC�ŒM�4 ™9œ9Ð5Ð5Ð5r   )r4   Úfromkeysr€   r.   r(   rq   )rˆ   ÚcleanÚplaceholdersr    ru   s        r   Úlatest_executionsr—   	  s  € àHÐH¥t§}¢}°WÑ'=Ô'=ÐHÑHÔH€EØð Øˆ	Ø—8’8Ð/Ð/¨Ð/Ñ/Ô/Ñ/Ô/€LÝ	‰Œð ˜4Ø�|Š|ðPØ$0ðPð Pð Pð
 ñ
ô 
÷ Š(‰*Œ*ð 	ðð ð ñ ô ð ð ð ð ð ð øøøð ð ð ð ð 6Ð5°Ð5Ñ5Ô5Ð5s   Á-BÂBÂB)r   r   )r    r   r   r!   )r   r*   )r/   r0   r   r1   )r8   r1   r7   r9   r   r!   )r?   r@   r   rA   )r?   r@   rF   rA   r   rG   )rS   rT   rU   rT   r   rV   )r`   rT   r   r1   )
r`   rT   rh   rG   rg   r9   r7   r9   r   r1   )r   r@   )rS   r9   rQ   r@   rx   r9   r   ry   )rS   rT   r   r1   )rˆ   r‰   r   rŠ   ),Ú__doc__Ú
__future__r   rJ   r   Ú	threadingr[   Ú
contextlibr   Útypingr   r   r   r   r	   Úhermes_constantsr
   Úhermes_timer   rY   Úresolver   rP   Ú_TERMINAL_STATESÚRLockr,   r\   r]   r^   r   r)   r.   r5   r>   rE   rM   rR   ra   rf   rl   rv   r…   r‡   r—   r   r   r   ú<module>r¢      su  ððð ð #Ð "Ð "Ð "Ð "Ð "à 	€	€	€	Ø €€€Ø Ð Ð Ð Ø €€€Ø %Ð %Ð %Ð %Ð %Ð %Ø 6Ð 6Ð 6Ð 6Ð 6Ð 6Ð 6Ð 6Ð 6Ð 6Ð 6Ð 6Ð 6Ð 6à ,Ð ,Ð ,Ð ,Ð ,Ð ,Ø *Ð *Ð *Ð *Ð *Ð *à!�/Ñ#Ô#×+Ò+Ñ-Ô-°Ñ6¸ÑH€ØÐ Ø5Ð Øˆ	ŒÑÔ€ØˆdŒj‰lŒlÔ€ð7ð 7ð 7ð 7ð
ð ð ð ðB ðð ð ñ „ðð(2ð 2ð 2ð 2ð
 LPð	ð 	ð 	ð 	ð 	ð 	ðð ð ð ð
9ð 
9ð 
9ð 
9ð	ð 	ð 	ð 	ðð ð ð ð,ð ð ð ð& AEØ&*ðð ð ð ð ð ð0"ð "ð "ð "ðL  $°"Ø'+ð'ð 'ð 'ð 'ð 'ð 'ð0%ð %ð %ð %ð
6ð 6ð 6ð 6ð 6ð 6r   