5 Lektionen: Systeme, die sich nachts selbst reparieren und aus Fehlern lernen.
Guards verhindern, dass ein Agent Schaden anrichtet. Aber Schaden, der von allein entsteht, um 3 Uhr nachts, ohne Zuschauer, dagegen tun Guards nichts. Ein Container crashed, ein Connection Pool ist erschöpft, eine Queue blockiert. Das Erste, was du davon erfährst, ist ein Kunde, der es bemerkt.
Self-Healing schließt diese Lücke. Eine Reihe von Skripten bemerkt, dass etwas nicht stimmt, und behebt es, ohne auf einen wachen Menschen zu warten.
Der offensichtliche Fehlermodus jedes Self-Healing-Systems: Der „Fix" verschlimmert die Lage und das System versucht denselben kaputten Fix immer erneut. Eine Restart-Schleife, die nie etwas erfolgreich neu startet, ist schlimmer als gar keine Automatisierung. Sie verbraucht Ressourcen und erzeugt Rauschen, während das eigentliche Problem unangetastet bleibt.
Deshalb gilt die harte Regel: Retries sind begrenzt. Wenn die Grenze erreicht ist, stoppt das System und eskaliert an einen Menschen, statt weiterzurotieren. Ein Emergency-Fix bleibt immer explizit temporär.
Kernprinzip: Erkennen, gegen parallele Reparaturen sperren, begrenzt reparieren, verifizieren und bei ausgeschöpftem Limit mit gesichertem Zustand eskalieren. Nie endlos retrien.
live-app-watchdog.sh (289 Zeilen): Enger, häufiger Zyklus. Prüft Container-Vorhandensein gegen Soll-Zustand, alle paar Minuten, rund um die Uhr.post-deploy-repair-loop.sh (187 Zeilen): Einmal nach jedem Deploy. HTTP-Check, visueller Check, Fix-Versuch, auf 3 Iterationen begrenzt.smart-auto-heal.sh (712 Zeilen): Breitester Scope. Läuft in längerem Zyklus über degradierte-aber-nicht-vollständig-down-Zustände.Die Übergabe zwischen ihnen ist eine Übergabe im Scope. Enge, häufige Prüfungen fangen offensichtliche Ausfälle schnell. Breitere, langsamere Prüfungen fangen die subtileren, die sich erst über ein längeres Beobachtungsfenster zeigen.
live-app-watchdog.sh hat einen spezifischen, engen Job: Live-Apps, die Kunden bedienen, vor dem Ausfall „der Container, der laufen soll, läuft nicht" schützen. Das Skript prüft Container-Status, Domain-Health und Soll-Zustand.
Ein Emergency-Container darf nur starten, wenn:
Ein exklusives Lock und eindeutige Instanzrollen verhindern parallele Starts, doppelte Worker und Split-Brain.
Kernprinzip: Das Wort „Emergency" leistet echte Arbeit. Ein Emergency-Container ist eine Brücke, kein Ziel. Er stellt den Dienst sofort wieder her, während das eigentliche Deployment-Problem während der Geschäftszeiten diagnostiziert wird. Einen Emergency-Container als permanenten Fix zu behandeln ist genau die Art von Abkürzung, die aus einer schlechten Nacht eine wiederkehrende macht.
Keines der drei Skripte berührt Kundendaten, keines modifiziert ein Datenbankschema und keines sendet Kommunikation an echte Nutzer. Das Behebungsvokabular bleibt gezielt eng und infrastrukturell: reversible Aktionen wie Prozess neustarten, Container aus bekanntem guten Image starten, Cache leeren oder einen Deploy-Schritt erneut ausführen.
#!/bin/bash
CONTAINER="deine-app"
DOMAIN="deine-app.example.de"
MAX_RETRIES=2
check_health() {
local status
status=$(curl -sS -o /dev/null -w "%{http_code}" \
"https://${DOMAIN}/api/health" 2>/dev/null)
[ "$status" = "200" ]
}
attempt=0
if ! docker ps --format '{{.Names}}' | grep -q "^${CONTAINER}$"; then
while [ "$attempt" -lt "$MAX_RETRIES" ]; do
attempt=$((attempt + 1))
echo "[$(date)] Container ${CONTAINER} nicht gefunden. Restart $attempt/$MAX_RETRIES"
docker start "$CONTAINER" 2>/dev/null || true
sleep 10
if check_health; then
echo "[$(date)] Health OK nach Restart."
exit 0
fi
done
echo "[$(date)] ESKALATION: ${CONTAINER} nach $MAX_RETRIES Versuchen nicht healthy."
# Hier: Push-Notification, Slack, E-Mail
exit 1
fi
*/5 * * * * /opt/scripts/watchdog.sh >> /var/log/watchdog.log 2>&1post-deploy-repair-loop.sh mit 187 Zeilen ist das straffste der drei Self-Healing-Skripte. Es läuft unmittelbar nach jedem Deploy und folgt einem einfachen Ablauf:
Die Schleife ist auf drei Iterationen begrenzt. Diese Begrenzung ist die wichtigste Zeile im gesamten Skript. Der Unterschied zwischen einem System, das sagt „Ich konnte das nicht reparieren, bitte schau hin" und einem System, das still Compute verbrennt.
Kernprinzip: „Bekannte Behebung" bedeutet nicht „lass den Agenten einen Fix improvisieren." Ein kleiner, gezielt begrenzter Satz vorab geprüfter Aktionen: Container neustarten, bestimmten Cache leeren, bestimmten Migrationsschritt erneut ausführen. Nicht um 2 Uhr nachts unter Druck kreativ werden.
Self-Healing ohne eine eigene Policy-Schicht wäre rücksichtslos. Ein Skript, das Container neustarten, Caches leeren und Behebungen automatisch ausführen darf, hat echtes destruktives Potenzial. Deshalb besitzt der Watchdog eine eigene enge Allowlist, Locking, begrenzte Versuche, Zustandsprüfungen und unveränderbare Logs.
#!/bin/bash
APP_URL="https://deine-app.example.de"
MAX_ATTEMPTS=3
attempt=0
while [ "$attempt" -lt "$MAX_ATTEMPTS" ]; do
http_code=$(curl -sS -o /dev/null -w "%{http_code}" "$APP_URL")
if [ "$http_code" = "200" ]; then
echo "Deploy verified healthy nach $attempt Repair-Versuch(en)."
exit 0
fi
attempt=$((attempt + 1))
echo "Health check failed (HTTP $http_code). Repair $attempt/$MAX_ATTEMPTS."
# Bekannte Behebungen (anpassen!)
docker restart "$(docker ps -q --filter name=deine-app)" 2>/dev/null
sleep 15
done
echo "ESKALATION: Deploy nicht healthy nach $MAX_ATTEMPTS Versuchen."
# Push-Notification senden
exit 1
Guards stoppen bekannte schlechte Aktionen und Self-Healing stellt bekannte Fehlzustände wieder her, doch keines von beiden wird von allein besser. Ein Guard bleibt exakt so intelligent wie am Tag seiner Niederschrift. Hörst du hier auf, ist das System stabil, aber statisch.
Das fehlende Stück ist die Self-Learning-Kette: Skripte, die bemerken, was passiert ist, entscheiden, ob es sich lohnt, die Erkenntnis zu behalten, und sie bei wiederholter Bewährung in eine permanente Regel umwandeln.
session-learner.sh (77 Zeilen): Läuft am Ende einer Session. Extrahiert Lernkandidaten: Etwas lief schief und wurde korrigiert. Etwas funktionierte, das vorher nicht offensichtlich war. Etwas brauchte drei Versuche, obwohl einer hätte reichen sollen.dreaming.sh (532 Zeilen): Läuft nächtlich gegen 02:00. Konsolidiert den Speicher des Tages, findet Duplikate, markiert veraltete Einträge, sucht nach Session-übergreifenden Mustern.crystallize-learnings.sh (64 Zeilen): Befördert einen bewährten Lernkandidaten von „vermerkt" zu „permanente Regel."learning-loop.sh (90 Zeilen): Verbindet die anderen drei zu einem kontinuierlichen Zyklus.Kernprinzip: Die ehrliche Unterscheidung zwischen „das System hat Guards" und „das System lernt": Guards sind ein Snapshot von allem, was du bereits herausgefunden hast. Die Learning-Kette ist der Mechanismus, durch den sich der Snapshot selbst aktualisiert.
Konsolidierung wiegt schwerer als Extraktion. Eine Lektion aus einer einzelnen Session zu extrahieren ist ein begrenztes Problem. Konsolidierung muss über alles bisher Angesammelte schauen: Sagt diese neue Notiz dasselbe wie eine bestehende? Stimmt die alte Notiz noch mit dem realen Systemverhalten überein? Verbirgt sich ein Muster über fünf separate Notizen hinweg?
dreaming.sh nächtlich laufen zu lassen statt nach jeder Session ist kein Zufall. Konsolidierung braucht einen Stapel angesammelten Materials und muss laufen, wenn nichts anderes aktiv in den Speicher schreibt.
learnings.md in deinem ProjektEin Lernkandidat wird nicht beim ersten Auftreten zur permanenten Regel. Er wird gespeichert mit Kontext, vorgeschlagener Regel, Nützlichkeits-Score und Run-Count.
Jedes Mal, wenn sich das Learning in einer späteren Session als nützlich erweist, steigt der Run-Count. Die Schwelle:
learning captured (session-learner.sh)
-> stored: { context, proposed_rule, score, runs: 0 }
-> each session where it helps again: runs += 1
-> human or system feedback: score updated
-> if score >= 4 AND runs >= 3: READY FOR REVIEW
-> provenance check + conflict scan + isolated tests + human approval
-> signed and versioned: CRYSTALLIZED -> written into permanent rules
Eine einzelne Beobachtung kann nicht zwischen einem echten Muster und einem einmaligen Zufall unterscheiden. Ein Fix, der einmal funktionierte, könnte aus einem Grund funktioniert haben, der nichts mit der vorgeschlagenen Regel zu tun hat. Drei separate, unabhängige Sessions filtern dieses Rauschen heraus.
Ein Regelsatz voller einmaliger Zufälle wäre über die Zeit genauso belastend wie gar keine Regeln. Anleitung, die mit Überzeugung falsch ist, schadet mehr als fehlende Anleitung, weil man ihr standardmäßig vertraut.
Ein Lernsystem, das immer nur Regeln hinzufügt, hat seinen eigenen Fehlermodus. Code ändert sich. Eine Regel, kristallisiert vor sechs Monaten, kann im Moment des Refactorings still falsch werden. Das ist die zweite Aufgabe von dreaming.sh: veraltete Einträge finden und zur Überprüfung markieren.
Kernprinzip: Ein Memory-System, das nur akkumuliert und nie bereinigt, wird irgendwann weniger vertrauenswürdig als gar kein Memory-System. Eine falsche Regel, formuliert mit Überzeugung, schadet mehr als eine fehlende. Die fehlende provoziert zumindest einen frischen Blick.
16.756 Vault-Dateien zu speichern ist nutzlos, wenn der Abruf der relevanten Datei länger dauert als die Antwort einfach neu abzuleiten. Memory Agent V2 löst das mit einem hybriden Ansatz: TF-IDF-Keyword-Matching kombiniert mit Embedding-basierter semantischer Suche. Keyword-Matching findet exakte Begriffsabgleiche. Embedding-Suche findet konzeptionell verwandte Notizen ohne ein einziges gemeinsames Wort. Zusammen decken sie gegenseitig ihre blinden Flecken ab.
learnings.md aus Übung 9 und füge jedem Eintrag hinzu: score: [1-5] und runs: [Anzahl]learnings.md nach Beförderungskandidaten filtertModul 2 abgeschlossen
Du hast jetzt: Self-Healing-Philosophie verstanden, einen Watchdog und eine Deploy-Verification gebaut, die Learning-Kette und den Kristallisierungs-Loop eingerichtet.