Ë
    tPêjÛ  ã                  ó<  — U d Z ddlmZ ddlZddlmZmZ ddlmZ ddl	m
Z
mZ ddlmZ ddlmZ dd	lmZ erdd
lmZ dZded<   dez  Zded<   dZded<   dZded<   dZded<   dZded<   dZded<    G d„ de«      Z eeedf   «      Zded<    G d„ d«      Zd!d „Z y)"a  
Live proxy worker census, one row per worker process.

Every uvicorn worker upserts its own row on a fixed heartbeat, so counting
rows with a recent heartbeat answers "how many workers share this database?"
without any coordination. The Admin UI's "no Redis" banner uses that count to
hide itself for deployments that are provably a single worker, where per-worker
rate limits, budgets, and router state are already global. All timestamps are
written and compared with the database's own clock, so pods with skewed clocks
still agree.
é    )ÚannotationsN)ÚTYPE_CHECKINGÚFinal)ÚTypeAdapter)ÚReadOnlyÚ	TypedDict)Úverbose_proxy_logger)Úuuid)ÚRoutingPrismaWrapper)ÚPrismaClienté<   r   Ú'PROXY_WORKER_HEARTBEAT_INTERVAL_SECONDSé   Ú$PROXY_WORKER_LIVENESS_WINDOW_SECONDSi  ÚSTALE_ROW_RETENTION_SECONDSz¬
INSERT INTO "LiteLLM_ProxyWorkerHeartbeat" (worker_id, hostname, last_heartbeat_at)
VALUES ($1, $2, NOW())
ON CONFLICT (worker_id) DO UPDATE SET last_heartbeat_at = NOW()
ÚBEAT_SQLzh
DELETE FROM "LiteLLM_ProxyWorkerHeartbeat"
WHERE last_heartbeat_at < NOW() - make_interval(secs => $1)
Ú	PRUNE_SQLz†
SELECT COUNT(*)::int AS live_workers FROM "LiteLLM_ProxyWorkerHeartbeat"
WHERE last_heartbeat_at > NOW() - make_interval(secs => $1)
Ú	COUNT_SQLzA
DELETE FROM "LiteLLM_ProxyWorkerHeartbeat" WHERE worker_id = $1
ÚDEREGISTER_SQLc                  ó   — e Zd ZU ded<   y)Ú_LiveWorkerCountRowzReadOnly[int]Úlive_workersN)Ú__name__Ú
__module__Ú__qualname__Ú__annotations__© ó    úl/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/proxy/db/proxy_worker_heartbeat.pyr   r   5   s   … ØÔr   r   .Ú_COUNT_ROWS_ADAPTERc                  ó&   — e Zd Zddd„Zdd„Zdd„Zy)ÚProxyWorkerHeartbeatNc                ó�   — || _         |xs t        t        j                  «       «      | _        t        j                  «       | _        y ©N)Úprisma_clientÚstrr
   Úuuid4Ú	worker_idÚsocketÚgethostnameÚhostname)Úselfr%   r(   s      r   Ú__init__zProxyWorkerHeartbeat.__init__=   s1   € Ø$1ˆÔØ%.Ò%C´#´d·j±j³lÓ2CˆŒÜ%×1Ñ1Ó3ˆ�r   c              ƒ  óh  K  — 	 | j                   j                  j                  t        | j                  | j
                  «      ƒ d {  –—†  | j                   j                  j                  t        t        «      ƒ d {  –—†  y 7 Œ;7 Œ# t        $ r }t        j                  d|«       Y d }~y d }~ww xY w­w)Nz'Proxy worker heartbeat write failed: %s)r%   ÚdbÚexecute_rawr   r(   r+   r   r   Ú	Exceptionr	   Údebug)r,   Úbeat_errs     r   ÚbeatzProxyWorkerHeartbeat.beatB   s‹   è ø€ ð	\Ø×$Ñ$×'Ñ'×3Ñ3´H¸d¿n¹nÈdÏmÉmÓ\×\Ð\Ø×$Ñ$×'Ñ'×3Ñ3´IÔ?ZÓ[×[Ñ[ð ]øØ[ùÜò 	\Ü ×&Ñ&Ð'PÐRZ×[Ñ[ûð	\üsS   ‚B2„AB ÁBÁ5B Á<BÁ=B ÂB2ÂB ÂB Â	B/ÂB*Â%B2Â*B/Â/B2c              ƒ  óâ   K  — 	 | j                   j                  j                  t        | j                  «      ƒ d {  –—†  y 7 Œ# t
        $ r }t        j                  d|«       Y d }~y d }~ww xY w­w)Nz,Proxy worker heartbeat deregister failed: %s)r%   r/   r0   r   r(   r1   r	   r2   )r,   Úderegister_errs     r   Ú
deregisterzProxyWorkerHeartbeat.deregisterI   sX   è ø€ ð	gØ×$Ñ$×'Ñ'×3Ñ3´NÀDÇNÁNÓS×SÒSùÜò 	gÜ ×&Ñ&Ð'UÐWe×fÑfûð	güs>   ‚A/„7A »A¼A Á A/ÁA Á	A,ÁA'Á"A/Á'A,Á,A/r$   )r%   r   r(   z
str | NoneÚreturnÚNone)r8   r9   )r   r   r   r-   r4   r7   r   r   r   r"   r"   <   s   „ ô4ó
\ôgr   r"   c              ƒ  ó6  K  — 	 | j                   }t        |t        «      r|j                  n|}|j	                  t
        t        «      ƒ d{  –—† }t        j                  |«      d   d   S 7 Œ# t        $ r }t        j                  d|«       Y d}~yd}~ww xY w­w)zè
    The number of workers with a recent heartbeat, or None when the database
    cannot answer. Callers must treat None as "unknown", not as zero. Always
    counts on the primary: a lagging read replica must never undercount.
    Nr   r   z'Live proxy worker count unavailable: %s)r/   Ú
isinstancer   ÚwriterÚ	query_rawr   r   r    Úvalidate_pythonr1   r	   r2   )r%   r/   Ú
primary_dbÚrowsÚ	count_errs        r   Úcount_live_proxy_workersrB   P   s†   è ø€ ðØ!×$Ñ$ˆÜ)3°BÔ8LÔ)M˜BŸIšIÐSUˆ
Ø&×0Ñ0´Ô<`Óa×aˆÜ"×2Ñ2°4Ó8¸Ñ;¸NÑKÐKð bùäò Ü×"Ñ"Ð#LÈiÔXÜûðüsA   ‚B„AA- ÁA+ÁA- Á*BÁ+A- Á-	BÁ6BÂBÂBÂB)r%   r   r8   z
int | None)!Ú__doc__Ú
__future__r   r)   Útypingr   r   Úpydanticr   Útyping_extensionsr   r   Úlitellm._loggingr	   Úlitellm._uuidr
   Ú'litellm.proxy.db.routing_prisma_wrapperr   Úlitellm.proxy.utilsr   r   r   r   r   r   r   r   r   r   Útupler    r"   rB   r   r   r   ú<module>rM      sÃ   ðò
õ #ã ß 'å  ß 1å 1Ý Ý HáÝ0à13Ð '¨Ó 3Ø./Ð2YÑ.YÐ $ eÓ YØ%)Ð ˜UÓ )ð€ˆ%ó ð€	ˆ5ó ð
€	ˆ5ó ð
€�ó ô
 ˜)ô  ñ )¨Ð/BÀCÐ/GÑ)HÓIÐ �UÓ I÷gñ gô(r   