#!/usr/bin/env bash # llm-heartbeat — garde « chaud » le tuyau LiteLLM ↔ llama-server. # # Pourquoi : llama-server ferme les connexions keep-alive inactives, mais LiteLLM # garde le socket mort dans son pool → la 1ʳᵉ requête après une pause part dans le # vide → timeout → 502 (cf. admin/incidents-llm-gpu.md). Un petit appel régulier # maintient la connexion vivante (et la re-crée AVANT la vraie demande si elle est morte). # # Double rôle (watchdog d'observation) : logge un échec → visible dans # `journalctl -u llm-heartbeat`. Déployé/géré par le rôle Ansible `litellm`. set -u URL="http://127.0.0.1:{{ litellm_port }}/v1/chat/completions" KEY="{{ litellm_master_key }}" MODEL="{{ llm_heartbeat_model }}" TIMEOUT="{{ llm_heartbeat_timeout }}" INTERVAL="{{ llm_heartbeat_interval }}" # `/no_think` + max_tokens:1 → génération quasi instantanée (~10 ms GPU), coût négligeable. payload="{\"model\":\"${MODEL}\",\"messages\":[{\"role\":\"user\",\"content\":\"ping /no_think\"}],\"max_tokens\":1}" fails=0 while true; do code=$(curl -s -m "$TIMEOUT" -o /dev/null -w '%{http_code}' \ "$URL" \ -H "Authorization: Bearer ${KEY}" \ -H "Content-Type: application/json" \ -d "$payload" 2>/dev/null) || code="000" if [ "$code" = "200" ]; then fails=0 else fails=$((fails + 1)) echo "heartbeat KO: HTTP ${code} (${MODEL}) — chaîne LLM non réactive (${fails} échec(s) consécutif(s))" fi sleep "$INTERVAL" done