Ë
    tPêj  ã            	       óÄ  — U d Z ddl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
 dZeed<   dZeed<   d	Zeed
<   dZeed<   defd„Zdededeeef   dz  fd„Zd#dededeedf   fd„Zdedefd„Zdededdfd„Zdeedf   dedeedf   fd„Zefdededdfd„Zefdeedf   deddfd„Zd#dededeedf   fd„Zdeddfd„Zd Zeed!<   dej@                  dz  fd"„Z!y)$a¨  Supervisor-side reaper for orphaned Prisma query-engine processes.

Each proxy worker owns a Prisma query-engine subprocess whose only cleanup
hook is an in-process ``atexit`` handler. When a multi-worker supervisor
(uvicorn's multiprocess manager, the gunicorn arbiter) force-kills a hung or
crashed worker, that handler never runs: the engine reparents to the nearest
subreaper (PID 1 in a container, which is the supervisor itself under the
standard docker entrypoint) and keeps its database connection pool
established forever, while the replacement worker opens a fresh pool. Over
repeated worker deaths the active database connections grow without bound.

The reaper runs only in the supervisor process, where a query-engine process
can never be a legitimate direct child: workers own their engines, and the
supervisor never starts one. Any direct child whose command name begins with
``query-engine`` is therefore an adopted orphan and is terminated
(SIGTERM, bounded grace, SIGKILL) and reaped. On Linux the supervisor also
marks itself a child subreaper so orphans reparent to it even when it is not
PID 1.

Linux-only by construction (``/proc`` scan, ``prctl``); a no-op elsewhere.
é    N)ÚFinal)Úverbose_proxy_loggerzquery-engineÚQUERY_ENGINE_COMM_PREFIXç      @ÚREAPER_SCAN_INTERVAL_SECONDSg      $@ÚSIGTERM_GRACE_SECONDSé$   ÚPR_SET_CHILD_SUBREAPERÚreturnc                  óØ   — t         j                  j                  d«      sy	 t        j                  dd¬«      } | j                  t        dddd«      }|dk(  S # t        t        f$ r Y yw xY w)zîMark this process as a child subreaper so orphaned descendants
    reparent to it instead of PID 1. Best-effort: when it fails (or on
    non-Linux) the reaper still covers the containerized case where the
    supervisor already is PID 1.ÚlinuxFNT)Ú	use_errnoé   r   )	ÚsysÚplatformÚ
startswithÚctypesÚCDLLÚprctlr
   ÚOSErrorÚAttributeError)ÚlibcÚresults     úi/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/proxy/db/query_engine_reaper.pyÚset_child_subreaperr   '   sj   € ô
 �<‰<×"Ñ" 7Ô+ØðÜ—k‘k $°$Ô7ˆØ—j‘jÜ" A q¨!¨Qó
ˆð ˜‰{ÐøÜ”^Ð$ò Ùðús   ¢4A ÁA)Á(A)ÚpidÚ	proc_rootc                 ó¶  — 	 t        |› d| › d�dd¬«      5 }|j                  «       }d d d «       j                  d«      }|j                  d«      }|dk(  s
|dk(  s||k  ry ||d	z   | }||d
z   d  j                  «       }t        |«      d
k  ry 	 t        |d	   «      }||fS # 1 sw Y   Œ{xY w# t        t        t        t
        f$ r Y y w xY w# t        $ r Y y w xY w)Nú/z/statÚasciiÚreplace)ÚencodingÚerrorsú(ú)éÿÿÿÿr   é   )ÚopenÚreadÚFileNotFoundErrorÚProcessLookupErrorÚPermissionErrorr   ÚfindÚrfindÚsplitÚlenÚintÚ
ValueError)	r   r   Ú	stat_fileÚdataÚlparenÚrparenÚcommÚfieldsÚppids	            r   Ú_read_comm_and_ppidr:   8   sù   € ðÜ�Y�K˜q   UÐ+°gÀiÔPð 	+ÐT]Ø#Ÿ.™.Ó*ˆD÷	+ð —I‘I˜c“N€FØ—J‘J˜s“O€FØ�‚|�v ’| v°¢ØØ�v ‘z FÐ+€DØ˜ !™˜Ð&×,Ñ,Ó.€FÜ
ˆ6ƒ{�Q‚ØðÜ˜& ™)“nˆð �ˆ:Ð÷!	+ð 	+ûäÔ1´?ÄGÐLò Ùðûô ò Ùðús9   ‚B- –B!§B- ÂC Â!B*Â&B- Â-C	ÃC	Ã	CÃCÚ
parent_pid.c                 óœ   ‡ ‡‡— 	 t        j                  ‰«      }d„ |D «       }t	        ˆˆ ˆfd„|D «       «      S # t        t        f$ r Y yw xY w)zÝPIDs of direct children of ``parent_pid`` whose command name marks
    them as Prisma query engines. In the supervisor these are always
    adopted orphans: live engines are children of workers, not of the
    supervisor.© c              3   óT   K  — | ]   }|j                  «       sŒt        |«      –— Œ" y ­w©N)Úisdigitr1   )Ú.0Úentrys     r   ú	<genexpr>z,list_orphaned_engine_pids.<locals>.<genexpr>V   s   è ø€ ÒP¨EÀÇÁÅœS ŸZÑPùs   ‚(˜(c              3   ó~   •K  — | ]4  }t        |‰«      xŠ�$‰d   ‰k(  r‰d   j                  t        «      r|–— Œ6 y ­w)Nr   r   )r:   r   r   )rA   r   Úinfor;   r   s     €€€r   rC   z,list_orphaned_engine_pids.<locals>.<genexpr>W   sJ   øè ø€ ò àÜ'¨¨YÓ7Ð7ˆDÐDØ�‰G�zÒ!Ø�‰G×ÑÔ7Ô8ô	 	ñùs   ƒ:=)ÚosÚlistdirr*   r   Útuple)r;   r   ÚentriesÚcandidate_pidsrE   s   ``  @r   Úlist_orphaned_engine_pidsrK   M   sV   ú€ ð
ÜŸ™ IÓ.ˆñ Q°WÔP€NÜõ à!ôó ð øô œwÐ'ò Ùðús   …9 ¹AÁ
Ac                 óŽ   — 	 t        j                  | t         j                  «      \  }}|| k(  S # t        $ r Y yt        $ r Y yw xY w)NT)rF   ÚwaitpidÚWNOHANGÚChildProcessErrorr   )r   Ú
reaped_pidÚ_s      r   Ú	_try_reaprR   `   sK   € ðÜŸ
™
 3¬¯
©
Ó3‰ˆ
�Að
 ˜ÑÐøô	 ò ÙÜò Ùðús   ‚'. ®	A¹AÁAÚsignumc                 óf   — 	 t        j                  | |«       y # t        t        t        f$ r Y y w xY wr?   )rF   Úkillr+   r,   r   )r   rS   s     r   Ú_send_signalrV   j   s.   € ðÜ
�‰��VÕøÜ¤´Ð9ò Ùðús   ‚ ™0¯0ÚpidsÚtimeout_secondsc                 óð   — t        j                  «       |z   }| }|rZt        j                  «       |k  rCt        d„ |D «       «      }|rt        j                  d«       |rt        j                  «       |k  rŒC|S )zoPoll until every PID is reaped or the shared deadline passes.
    Returns the PIDs still alive at the deadline.c              3   ó8   K  — | ]  }t        |«      rŒ|–— Œ y ­wr?   )rR   )rA   r   s     r   rC   z _await_reaped.<locals>.<genexpr>w   s   è ø€ ÒI #¼)ÀC½.œ#ÑIùs   ‚“gš™™™™™É?)ÚtimeÚ	monotonicrH   Úsleep)rW   rX   ÚdeadlineÚ	remainings       r   Ú_await_reapedr`   q   sd   € ô —n‘nÓ&¨Ñ8€HØ€IÙ
œŸ™Ó(¨8Ò3ÜÑI¨ÔIÓIˆ	ÙÜ�J‰J�sŒOñ œŸ™Ó(¨8Ó3ð Ðó    Úgrace_secondsc                 ó    — t        | f|¬«       y)z{SIGTERM the orphaned engine, escalate to SIGKILL after the grace
    period, and reap it so it does not linger as a zombie.)rb   N)Úterminate_and_reap_all)r   rb   s     r   Úterminate_and_reapre   }   s   € ô ˜C˜6°Ö?ra   c                 óR  — | D ]2  }t        j                  d|«       t        |t        j                  «       Œ4 t        | |«      }|sy|D ]3  }t        j                  d||«       t        |t        j                  «       Œ5 t        |d«      }|D ]  }t        j                  d|«       Œ y)a  Terminate a batch of orphaned engines concurrently: SIGTERM all of
    them, share one grace period, SIGKILL the stragglers, and reap. The
    shared deadline keeps cleanup time bounded when several workers die
    at once instead of paying the grace period once per orphan.zXReaping orphaned prisma query-engine PID %s (its worker process exited without cleanup).NzZOrphaned prisma query-engine PID %s did not exit within %.1fs of SIGTERM; sending SIGKILL.r   zROrphaned prisma query-engine PID %s survived SIGKILL; will retry on the next scan.)r   ÚwarningrV   ÚsignalÚSIGTERMr`   ÚSIGKILLÚerror)rW   rb   r   Ú	survivorsÚ
unkillables        r   rd   rd   ƒ   s²   € ð ò *ˆÜ×$Ñ$ØfØô	
ô 	�Sœ&Ÿ.™.Õ)ð*ô % T¨=Ó9€IÙØØò *ˆÜ×$Ñ$ØhØØô	
ô
 	�Sœ&Ÿ.™.Õ)ð*ô & i°Ó5€JØò 
ˆÜ×"Ñ"Ø`Øõ	
ñ
ra   c                 ó:   — t        | |¬«      }|rt        |«       |S )z5One scan-and-reap pass. Returns the PIDs it acted on.)r   )rK   rd   )r;   r   Úorphaned_pidss      r   Úreap_orphaned_enginesrp   £   s   € ä4°ZÈ9ÔU€MÙÜ˜}Ô-ØÐra   c                 ó¨   — 	 	 t        | «       t	        j
                  t        «       Œ&# t        $ r }t        j                  d|«       Y d }~Œ>d }~ww xY w)Nz%Orphaned query-engine scan failed: %s)rp   Ú	Exceptionr   Údebugr[   r]   r   )r;   Ú
scan_errors     r   Ú_reaper_loopru   «   sP   € Ø
ð	\Ü! *Ô-ô 	�
‰
Ô/Ô0ð øô ò 	\Ü ×&Ñ&Ð'NÐPZ×[Ñ[ûð	\ús   ƒ( ¨	A±AÁAz"litellm-orphan-query-engine-reaperÚREAPER_THREAD_NAMEc                  ó„  — t         j                  j                  d«      syt        d„ t	        j
                  «       D «       d«      } | �| S t        «        t	        j                  t        t        j                  «       fdt        ¬«      }|j                  «        t        j                  dt        j                  «       «       |S )a¤  Start the reaper daemon thread in the supervisor process.

    Must only be called from a process that never hosts the proxy app
    itself (uvicorn with ``workers > 1``, the gunicorn arbiter): with a
    single in-process uvicorn worker the query engine is a legitimate
    direct child and must not be touched. Idempotent: a reaper already
    running in this process is returned instead of starting a second one.
    r   Nc              3   óH   K  — | ]  }|j                   t        k(  sŒ|–— Œ y ­wr?   )Únamerv   )rA   Úthreads     r   rC   z,start_query_engine_reaper.<locals>.<genexpr>Ã   s   è ø€ ÒY�F°v·{±{ÔFXÓ7XŒÑYùs   ‚"›"T)ÚtargetÚargsÚdaemonry   zEStarted orphaned prisma query-engine reaper in supervisor process %s.)r   r   r   ÚnextÚ	threadingÚ	enumerater   ÚThreadru   rF   Úgetpidrv   Ústartr   rE   )ÚexistingÚreaper_threads     r   Ústart_query_engine_reaperr†   ·   sž   € ô �<‰<×"Ñ" 7Ô+ØÜÙYœi×1Ñ1Ó3ÔYØó€Hð ÐØˆÜÔÜ$×+Ñ+ÜÜ�i‰i‹kˆ^ØÜô	€Mð ×ÑÔÜ×ÑØOÜ
�	‰	‹ôð Ðra   )z/proc)"Ú__doc__r   rF   rh   r   r   r[   Útypingr   Úlitellm._loggingr   r   Ú__annotations__r   r   r
   Úboolr   r1   ÚstrrH   r:   rK   rR   rV   Úfloatr`   re   rd   rp   ru   rv   r�   r†   r=   ra   r   ú<module>rŽ      s¬  ðòó, Û 	Û Û 
Û Û Ý å 1à"0Ð ˜%Ó 0Ø&)Ð ˜eÓ )Ø#Ð �uÓ #Ø "Ð ˜Ó "ð˜Tó ð"˜Sð ¨Sð °U¸3À¸8±_ÀtÑ5Kó ñ*¨#ð ¸#ð ÈEÐRUÐWZÐRZÉOó ð&�3ð ˜4ó ð�cð  3ð ¨4ó ð	˜˜c 3˜h™ð 	¸%ð 	ÀEÈ#ÈsÈ(ÁOó 	ð 9Nñ @˜Cð @°ð @ÐRVó @ð 1ñ
Ø
��S�‰/ð
àð
ð 
ó
ñ@ cð °cð ÈÈcÐSVÈhÉó ð1˜Sð 1 Tó 1ð AÐ �EÓ @ð 9×#3Ñ#3°dÑ#:ô ra   