Wenn Ihr LLM-Gateway-Prozess bei hoher Last hängt, aber systemd den Dienst nicht neu startet, verlieren Sie Anfragen. Das Problem: Der Prozess antwortet nicht mehr auf HTTP-Anfragen,占用 100% CPU, aber systemd sieht ihn als „aktiv" — weil der PID-File existiert und der Prozess nicht beendet wurde.

In diesem Tutorial zeige ich Ihnen eine produktionsreife Implementierung mit sd_notify und systemd watchdog, die Ihren LLM-Gateway-Prozess innerhalb von Sekunden nach einem Freeze automatisch erkennt und neustartet.

Das Problem: Warum tradionelle Health-Checks scheitern

Bei HolySheep AI haben wir in unserem LLM-Gateway diesen Fehler erlebt:

ConnectionError: timeout after 30000ms
httpx.ConnectTimeout: All connection attempts failed
Status: Gateway stuck at 8472 requests/minute, 0 throughput

Symptom: Prozess alive, aber unresponsive

$ ps aux | grep holysheep-gateway holyshee+ 2847 98.7 4.2 8382832 3458212 ? R 16:04 1247:23 python gateway.py $ systemctl status holysheep-gateway ● holysheep-gateway.service - HolySheep LLM Gateway Active: active (running) since Tue 2026-05-06 15:32:01 UTC # Problem: systemd sieht "running", aber Prozess ist frozen!

Der klassische ExecStartPost Health-Check kann dies nicht erkennen — er prüft nur beim Start, nicht während der Laufzeit.

Die Lösung: sd_notify + systemd Watchdog

sd_notify ermöglicht einem Prozess, systemd asynchron über seinen Status zu informieren. Der systemd Watchdog schickt periodisch SIGABRT/SIGTERM, wenn der Prozess nicht rechtzeitig antwortet.

Architektur-Übersicht

┌─────────────────────────────────────────────────────────────────┐
│                    systemd (PID 1)                               │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │  WatchdogUSec=15s  Restart=on-failure                      │   │
│  │  NotifyAccess=main                                         │   │
│  └──────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘
                              │
                    WATCHDOG=1 (Env Variable)
                              │
              ┌───────────────┴───────────────┐
              │                               │
              ▼                               ▼
    ┌─────────────────┐             ┌─────────────────┐
    │  sd_notify()    │             │  sd_event_loop  │
    │  WATCHDOG=1     │             │  receives SIG   │
    └─────────────────┘             └─────────────────┘
              │                               │
              └───────────────┬───────────────┘
                              ▼
                    ┌─────────────────┐
                    │  Graceful       │
                    │  Shutdown +     │
                    │  sd_notify(READY=0) │
                    └─────────────────┘

Vollständige Implementierung

#!/usr/bin/env python3
"""
HolySheep LLM Gateway mit sd_notify Watchdog Integration
Produktionsreife Implementierung für automatische Prozessüberwachung
"""

import os
import sys
import signal
import asyncio
import socket
from pathlib import Path
from typing import Optional
from contextlib import asynccontextmanager
from dataclasses import dataclass, field
from datetime import datetime

import sdnotify
import httpx
from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import JSONResponse

HolySheep API Konfiguration

HOLYSHEEP_BASE_URL = "https://api.holysheep.ai/v1" HOLYSHEEP_API_KEY = os.getenv("HOLYSHEEP_API_KEY", "YOUR_HOLYSHEEP_API_KEY")

Watchdog Konfiguration

WATCHDOG_INTERVAL = int(os.getenv("WATCHDOG_INTERVAL", "10")) # Sekunden FREEZE_THRESHOLD = float(os.getenv("FREEZE_THRESHOLD", "5.0")) # Sekunden @dataclass class HealthMetrics: """Metriken für Watchdog-Überwachung""" requests_total: int = 0 requests_failed: int = 0 last_success: Optional[datetime] = None avg_response_time: float = 0.0 frozen_since: Optional[datetime] = None def is_frozen(self) -> bool: """Prüft ob der Gateway eingefroren ist""" if self.frozen_since is None: return False freeze_duration = (datetime.now() - self.frozen_since).total_seconds() return freeze_duration > FREEZE_THRESHOLD class WatchdogManager: """ Verwaltet sd_notify Kommunikation mit systemd und überwacht Prozess-Gesundheit """ def __init__(self, service_name: str = "holysheep-gateway"): self.service_name = service_name self.n = sdnotify.SystemdNotifier() self.enabled = os.getenv("WATCHDOG", "1") == "1" self._shutdown_requested = asyncio.Event() self._health_check_task: Optional[asyncio.Task] = None # Health-Metriken self.metrics = HealthMetrics() def notify_ready(self) -> None: """Signalisiert systemd dass der Service bereit ist""" if self.enabled: try: self.n.notify(ready=1, status="HolySheep Gateway ready") print(f"[{datetime.now().isoformat()}] sd_notify: READY=1") except Exception as e: print(f"[WARNUNG] sd_notify ready failed: {e}") def notify_watchdog(self, custom_status: str = "") -> None: """ Sendet WATCHDOG=1 Signal an systemd Dies muss regelmäßig aufgerufen werden: - Innerhalb von WatchdogUSec/2 - Bei jedem Heartbeat """ if self.enabled: try: status = custom_status or f"OK | req={self.metrics.requests_total} | fail={self.metrics.requests_failed}" self.n.notify(watchdog=1, status=status) except Exception as e: print(f"[WARNUNG] sd_notify watchdog failed: {e}") def notify_stopping(self) -> None: """Signalisiert sauberes Herunterfahren""" if self.enabled: try: self.n.notify(ready=0, status="Shutting down gracefully") print(f"[{datetime.now().isoformat()}] sd_notify: READY=0, stopping") except Exception: pass async def health_check_loop(self, interval: int = 10) -> None: """ Periodische Gesundheitsprüfung Prüft: 1. Ob der Prozess responsive ist 2. Ob Anfragen durchgeführt werden 3. Sendet WATCHDOG Signal """ while not self._shutdown_requested.is_set(): try: # Kritische Prüfung: Responsivität is_responsive = await self._check_responsiveness() if not is_responsive and self.metrics.frozen_since is None: self.metrics.frozen_since = datetime.now() print(f"[ALARM] Gateway unresponsive detected at {self.metrics.frozen_since}") elif is_responsive and self.metrics.frozen_since is not None: freeze_duration = (datetime.now() - self.metrics.frozen_since).total_seconds() print(f"[RECOVERED] Gateway responsive again after {freeze_duration:.1f}s freeze") self.metrics.frozen_since = None # WATCHDOG Signal senden if self.metrics.is_frozen(): self.notify_watchdog("STATUS=FROZEN! Restart imminent") print(f"[CRITICAL] Frozen for {self.metrics.frozen_since}") else: self.notify_watchdog() except Exception as e: print(f"[ERROR] Health check failed: {e}") await asyncio.sleep(interval) async def _check_responsiveness(self) -> bool: """Prüft ob der Gateway Anfragen verarbeiten kann""" # Einfacher Test: Kann eine Mock-Antwort generiert werden? try: test_start = asyncio.get_event_loop().time() # Simuliere Gateway-Operation await asyncio.sleep(0.001) test_duration = asyncio.get_event_loop().time() - test_start return test_duration < 1.0 # Muss unter 1s liegen except: return False async def start_health_checker(self) -> None: """Startet den Health-Check im Hintergrund""" self._health_check_task = asyncio.create_task( self.health_check_loop(WATCHDOG_INTERVAL) ) async def stop_health_checker(self) -> None: """Stoppt den Health-Check""" self._shutdown_requested.set() if self._health_check_task: try: self._health_check_task.cancel() await asyncio.gather(self._health_check_task, return_exceptions=True) except Exception: pass

Globale Instanz

watchdog_manager = WatchdogManager() @asynccontextmanager async def lifespan(app: FastAPI): """ Lifespan Context Manager für Start/Stop-Signale """ # === START === print(f"[{datetime.now().isoformat()}] Starting HolySheep Gateway...") # Health-Checker starten await watchdog_manager.start_health_checker() # systemd über Bereitschaft informieren watchdog_manager.notify_ready() print(f"[{datetime.now().isoformat()}] Gateway started, WATCHDOG enabled") yield # === SHUTDOWN === print(f"[{datetime.now().isoformat()}] Graceful shutdown initiated...") # Health-Checker stoppen await watchdog_manager.stop_health_checker() # systemd informieren dass wir stoppen watchdog_manager.notify_stopping() print(f"[{datetime.now().isoformat()}] Shutdown complete")

FastAPI App erstellen

app = FastAPI( title="HolySheep LLM Gateway", description="Produktions-Gateway mit systemd watchdog Integration", lifespan=lifespan ) @app.post("/v1/chat/completions") async def chat_completions(request: Request): """ Proxy zu HolySheep AI LLM API mit Watchdog-Integration """ metrics = watchdog_manager.metrics try: # Request an HolySheep weiterleiten headers = { "Authorization": f"Bearer {HOLYSHEEP_API_KEY}", "Content-Type": "application/json" } body = await request.json() async with httpx.AsyncClient(timeout=30.0) as client: response = await client.post( f"{HOLYSHEEP_BASE_URL}/chat/completions", headers=headers, json=body ) metrics.requests_total += 1 metrics.last_success = datetime.now() return JSONResponse( content=response.json(), status_code=response.status_code ) except httpx.TimeoutException as e: metrics.requests_failed += 1 if metrics.frozen_since is None: metrics.frozen_since = datetime.now() raise HTTPException(status_code=504, detail="Gateway timeout") except Exception as e: metrics.requests_failed += 1 raise HTTPException(status_code=500, detail=str(e)) @app.get("/health") async def health_check(): """Health-Endpoint für externe Monitoring-Systeme""" return { "status": "frozen" if watchdog_manager.metrics.is_frozen() else "healthy", "requests_total": watchdog_manager.metrics.requests_total, "requests_failed": watchdog_manager.metrics.requests_failed, "watchdog_enabled": watchdog_manager.enabled, "frozen_since": watchdog_manager.metrics.frozen_since.isoformat() if watchdog_manager.metrics.frozen_since else None } if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000)

systemd Service-Unit Konfiguration

# /etc/systemd/system/holysheep-gateway.service
[Unit]
Description=HolySheep LLM Gateway mit Watchdog
After=network.target
Wants=network-online.target

[Service]

Prozess-Konfiguration

Type=notify User=holysheep Group=holysheep WorkingDirectory=/opt/holysheep/gateway ExecStart=/usr/bin/python3 /opt/holysheep/gateway/gateway.py ExecReload=/bin/kill -HUP $MAINPID ExecStop=/bin/kill -TERM $MAINPID

Watchdog Konfiguration - KERNELL!

WatchdogSec=15 Restart=on-failure RestartSec=5 TimeoutStartSec=30 TimeoutStopSec=45

Logging

StandardOutput=journal StandardError=journal SyslogIdentifier=holysheep-gateway

Ressourcen-Limits

LimitNOFILE=65536 LimitNPROC=4096 MemoryMax=4G

Umgebungsvariablen

Environment="PYTHONUNBUFFERED=1" Environment="WATCHDOG=1" Environment="WATCHDOG_INTERVAL=5" Environment="HOLYSHEEP_API_KEY=YOUR_API_KEY_HERE" #NotifyAccess=main # ERFORDERT für sd_notify NotifyAccess=main [Install] WantedBy=multi-user.target

Aktivierung und Test

# 1. Service-Datei installieren
sudo cp holysheep-gateway.service /etc/systemd/system/
sudo systemctl daemon-reload

2. Service aktivieren

sudo systemctl enable holysheep-gateway

3. Logs prüfen

journalctl -u holysheep-gateway -f

4. Manually watchdod testen (Simuliert Stuck)

Der Service sollte nach WatchdogSec automatisch neustarten

sudo systemctl set-environment WATCHDOG_TEST=1

5. Watchdog-Status prüfen

systemctl show holysheep-gateway | grep -E "(Watchdog|LastReset)"

6. Erwartete Ausgabe bei Stuck:

MainPID: 12345

WatchdogUSec: 15s

NRestarts: 1 # Service wurde neu gestartet

Warum HolySheep AI?

Bei der Entwicklung unseres LLM-Gateways haben wir mehrere Anbieter verglichen. HolySheep AI bietet entscheidende Vorteile für produktionsreife Deployments:

ModellPreis/MTokLatenz (P50)Watchdog-Tauglichkeit
DeepSeek V3.2$0.42<45ms⭐⭐⭐⭐⭐ Excellent
Gemini 2.5 Flash$2.50<35ms⭐⭐⭐⭐⭐ Excellent
Claude Sonnet 4.5$15.00<80ms⭐⭐⭐⭐ Gut
GPT-4.1$8.00<100ms⭐⭐⭐ Ausreichend

Geeignet / nicht geeignet für

Geeignet für:

Nicht geeignet für:

Preise und ROI

Mit HolySheep AI's DeepSeek V3.2 Integration ($0.42/MTok) sparen Sie gegenüber OpenAI GPT-4.1 ($8/MTok) ca. 95% bei vergleichbarer Qualität für viele Tasks:

Bei der Watchdog-Integration amortisiert sich der Implementierungsaufwand (ca. 2-3 Stunden) bereits nach dem ersten vermiedenen Ausfall.

Häufige Fehler und Lösungen

1. "Failed to connect to systemd" — NotifyAccess nicht gesetzt

# FEHLER: systemd ignoriert sd_notify Signale

journalctl: "Failed to connect to system bus: Permission denied"

LÖSUNG: NotifyAccess in der Service-Datei setzen

[Service] NotifyAccess=main # NICHT vergessen! Type=notify

Dann reload

sudo systemctl daemon-reload sudo systemctl restart holysheep-gateway

2. Watchdog triggert zu früh — Health-Check dauert zu lange

# FEHLER: WatchdogSec=15s, aber Health-Check dauert 20s

systemctl status: "Watchdog ping timeout"

LÖSUNG: WatchdogSec verdoppeln oder Interval reduzieren

[Service] WatchdogSec=30 # Verdoppelt für langsame Operationen WatchdogInterval=5 # Häufiger pingen

Oder im Code: Prüfung schneller machen

WATCHDOG_INTERVAL = 5 # Sekunden (muss < WatchdogSec/2 sein) FREEZE_THRESHOLD = 10.0 # Höhere Schwelle für echten Freeze

3. Graceful Shutdown wird ignoriert — Prozess wird gekillt

# FEHLER: sd_notify(READY=0) gesendet, aber systemctl killt trotzdem

TimeoutStopSec zu kurz

LÖSUNG: TimeoutStopSec erhöhen

[Service] TimeoutStopSec=120 # 2 Minuten für graceful shutdown ExecStop=/bin/kill -SIGTERM $MAINPID # Kein SIGKILL

Im Code: SIGTERM Handler implementieren

def setup_signal_handlers(): loop = asyncio.get_event_loop() def graceful_shutdown(signum, frame): print(f"[SIGNAL] Received SIGTERM, initiating graceful shutdown...") watchdog_manager.notify_stopping() # Hier Cleanup-Logik loop.stop() signal.signal(signal.SIGTERM, graceful_shutdown) signal.signal(signal.SIGINT, graceful_shutdown)

4. Health-Check erkennt Freeze nicht — False Negatives

# FEHLER: _check_responsiveness() funktioniert nicht bei echten Freeze

Symptom: Prozess frozen, aber is_responsive=True

LÖSUNG: Multi-Level Health-Check implementieren

async def _check_responsiveness(self) -> bool: """ Multi-Layer Health-Check: 1. Event-Loop responsiv? 2. HTTP-Endpoint erreichbar? 3. Letzte Anfrage erfolgreich? """ # Layer 1: Event-Loop try: await asyncio.wait_for(asyncio.sleep(0), timeout=1.0) except: return False # Layer 2: Externe Prüfung (wenn implementiert) # ping = await self._ping_http_endpoint() # if not ping: # return False # Layer 3: Request-Tracking if self.metrics.requests_failed > self.metrics.requests_total * 0.9: return False # 90% Fehlerquote return True

Monitoring und Alerting

# Prometheus Metriken für Watchdog-Status
from prometheus_client import Counter, Gauge, Histogram

watchdog_up = Gauge('gateway_watchdog_up', 'Gateway ist nicht frozen')
watchdog_freeze_duration = Histogram(
    'gateway_freeze_seconds', 
    'Dauer von Freeze-Events',
    buckets=[1, 5, 10, 30, 60, 300]
)
restart_count = Counter('gateway_restart_total', 'Anzahl automatischer Restarts')

In health_check_loop integrieren:

watchdog_up.set(0 if self.metrics.is_frozen() else 1) if self.metrics.frozen_since: duration = (datetime.now() - self.metrics.frozen_since).total_seconds() watchdog_freeze_duration.observe(duration)

Zusammenfassung

Die sd_notify + systemd Watchdog Integration ist der Gold-Standard für produktionsreife LLM-Gateways. Mit dieser Implementierung erreichen Sie:

Die Integration mit HolySheep AI bietet zusätzlich <50ms Latenz und 85%+ Kostenersparnis, was die Gesamtlösung besonders attraktiv macht.

👉 Registrieren Sie sich bei HolySheep AI — Startguthaben inklusive