Im September 2025 erlebte eines der kritischsten Infrastrukturunternehmen des Internets einen Ausfall, der nicht von ausgefeilten Hackern, massiven DDoS-Angriffen oder Serverausfällen verursacht wurde. Stattdessen wurde Cloudflare – das Unternehmen, das routinemäßig Terabit-Angriffe abwehrt und Millionen von Websites online hält – von einem grundlegenden React-Programmierfehler lahmgelegt, den viele Junior-Entwickler in ihrer ersten Woche zu vermeiden lernen.
Die schockierende Realität
Die Ironie ist fast komisch: Cloudflare, das erfolgreich 7,3 Terabit pro Sekunde DDoS-Angriffe abgewehrt hat, wurde von einem React useEffect Hook mit einem fehlerhaften Dependency-Array offline genommen. Das war keine Elite-Truppe staatlicher Hacker – es war ein klassisches Frontend-Entwicklungs-Antimuster, das eine Endlosschleife von API-Aufrufen erzeugte.
Quelle: Die technischen Details und der Zeitplan, auf die in diesem Artikel verwiesen wird, basieren auf Cloudflares offiziellem Vorfallsbericht: “A deep dive into Cloudflare’s September 12, 2025 dashboard and API outage”
Den technischen Fehler verstehen
Das problematische Code-Muster
Das Problem stammte von diesem häufigen React-Muster:
// Vereinfachte Version des problematischen Codes
function Dashboard() {
const params = { // Dieses Objekt wird bei jedem Render neu erstellt
organizationId: user.orgId,
filters: currentFilters
};
useEffect(() => {
// Diese Funktion ruft die API auf
fetchDashboardData(params);
}, [params]); // ← Hier ist das Problem
return "Dashboard gerendert";
}
Warum das eine Endlosschleife erzeugt
Der useEffect Hook vergleicht Abhängigkeiten mit flachem Vergleich. Hier ist, was passiert:
- Komponente rendert → Erstellt neues
params-Objekt - useEffect läuft → Ruft Daten ab, aktualisiert möglicherweise State
- State-Update triggert Re-Render → Erstellt ein weiteres neues
params-Objekt - React vergleicht Abhängigkeiten →
params-Referenz hat sich geändert - useEffect läuft wieder → Zurück zu Schritt 2, erzeugt eine Endlosschleife
Warum wird das params-Objekt jedes Mal neu erstellt?
In JavaScript erstellen Objektliterale wie { organizationId: user.orgId, filters: currentFilters } jedes Mal ein neues Objekt im Speicher, wenn sie ausgeführt werden. Selbst wenn die Werte darin identisch sind, ist die Objektreferenz unterschiedlich.
// Jedes Mal, wenn diese Funktion läuft, wird ein NEUES Objekt erstellt
const params = { organizationId: user.orgId, filters: currentFilters };
// Das ist äquivalent zu:
const params = new Object();
params.organizationId = user.orgId;
params.filters = currentFilters;
Vergleich von Speicherreferenzen:
// Diese Objekte haben den gleichen Inhalt, aber unterschiedliche Speicherreferenzen
const obj1 = { name: "John" };
const obj2 = { name: "John" };
console.log(obj1 === obj2); // false - unterschiedliche Speicherorte
// Nur die gleiche Referenz gibt true zurück
const obj3 = obj1;
console.log(obj1 === obj3); // true - gleiche Speicherreferenz
Reacts useEffect verwendet Object.is() (ähnlich wie ===), um Abhängigkeiten zu vergleichen. Da bei jedem Render ein neues params-Objekt erstellt wird, denkt React, die Abhängigkeit hat sich geändert, obwohl die Werte darin möglicherweise identisch sind.
Das Ausmaß des Problems
Laut Cloudflares Vorfallsbericht führte dieser einfache Fehler zu:
- Tausenden von API-Aufrufen pro Minute von einer einzigen Dashboard-Sitzung
- Vollständiger API-Überlastung, multipliziert über alle Benutzer
- Kaskadierende Ausfälle in ihrer gesamten Infrastruktur
- Globalem Ausfall, der Millionen von Websites betraf
Die korrekten Lösungen
Lösung 1: Die Abhängigkeit memoizen
import { useMemo, useEffect } from 'react';
function Dashboard() {
const params = useMemo(() => ({
organizationId: user.orgId,
filters: currentFilters
}), [user.orgId, currentFilters]); // Nur neu erstellen, wenn sich diese ändern
useEffect(() => {
fetchDashboardData(params);
}, [params]);
return "Dashboard gerendert";
}
Lösung 2: Die Abhängigkeiten aufteilen
function Dashboard() {
useEffect(() => {
const params = {
organizationId: user.orgId,
filters: currentFilters
};
fetchDashboardData(params);
}, [user.orgId, currentFilters]); // Direkte Abhängigkeiten
return "Dashboard gerendert";
}
Lösung 3: useCallback für Funktionen verwenden
import { useCallback, useEffect } from 'react';
function Dashboard() {
const fetchData = useCallback(async () => {
const params = {
organizationId: user.orgId,
filters: currentFilters
};
await fetchDashboardData(params);
}, [user.orgId, currentFilters]);
useEffect(() => {
fetchData();
}, [fetchData]);
return "Dashboard gerendert";
}
Die breiteren Engineering-Lektionen
1. Code-Review-Fehler
Wie hat diese offensichtliche Endlosschleife es in die Produktion geschafft? Der Vorfall hebt mehrere Engineering-Prozess-Fehler hervor:
- Lokale Entwicklungstests hätten sofort Tausende von Netzwerkanfragen zeigen müssen
- Code-Review-Prozesse sollten grundlegende React-Antimuster erkennen
- Staging-Umgebungen sollten Produktionslastmuster replizieren
- Überwachungssysteme sollten bei ungewöhnlichen API-Nutzungsmustern alarmieren
2. Das Thundering-Herd-Problem
Als Cloudflare versuchte, das Problem durch das Löschen von Benutzersitzungen zu beheben, erzeugten sie versehentlich ein “Thundering Herd”-Problem – Millionen von Benutzern authentifizierten sich gleichzeitig neu, als der Dienst wieder online kam, was einen zweiten Ausfall verursachte.
3. Rate Limiting und Circuit Breaker
Der Vorfall offenbarte, dass Cloudflares internen APIs fehlten:
- Rate Limiting zur Verhinderung von Missbrauch
- Circuit Breaker für graceful Failure unter Last
- Automatische Rollback-Mechanismen für problematische Deployments
Präventionsstrategien
Für Entwickler
- ESLint-Regeln verwenden wie
exhaustive-deps, um Abhängigkeitsprobleme zu erkennen - React Developer Tools installieren, um Komponenten-Re-Renders zu überwachen
- Netzwerküberwachung hinzufügen, um ungewöhnliche API-Muster während der Entwicklung zu erkennen
- Defensive Programmierung üben mit korrekten Error Boundaries
Für Engineering-Teams
- Schrittweise Rollouts implementieren anstelle von sofortigen globalen Deployments
- Ordnungsgemäße Überwachung einrichten für API-Nutzungsmuster
- Code-Review-Checklisten etablieren für häufige React-Antimuster
- Last-Test-Umgebungen erstellen, die echte Nutzung simulieren
Essenzielle ESLint-Konfiguration
{
"extends": ["plugin:react-hooks/recommended"],
"rules": {
"react-hooks/exhaustive-deps": "error"
}
}
Ein kritischer Lernmoment
Dieser Vorfall dient als kraftvolle Erinnerung daran, wie grundlegende Programmierfehler massive globale Auswirkungen haben können. Der Ausfall betraf Millionen von Websites und unzählige Unternehmen weltweit, alles durch einen Fehler, der mit ordnungsgemäßem Tooling und Prozessen hätte erkannt werden können.
Wichtige Erkenntnisse
- Grundlegendes Wissen zählt — Selbst im Enterprise-Maßstab sind grundlegende Programmierprinzipien kritisch
- Tooling ist essentiell — ESLint, React DevTools und ordnungsgemäße Überwachung verhindern diese Probleme
- Prozessfehler verstärken technische Fehler — Mehrere Sicherheitsnetze versagten gleichzeitig
- Schrittweises Deployment rettet Leben — Sofortige globale Rollouts sind gefährlich für kritische Infrastruktur
- Reacts Macht erfordert Verantwortung — Die Flexibilität des Frameworks erfordert disziplinierte Entwicklungspraktiken
Weitermachen
Cloudflare hat seitdem implementiert:
- Argo Rollouts für automatische Deployment-Rollbacks
- Verbesserte Überwachung für API-Nutzungsmuster
- Bessere Rate-Limiting- und Circuit-Breaker-Muster
- Verbesserte Code-Review-Prozesse für Frontend-Änderungen
Der Vorfall dient als kraftvolle Erinnerung daran, dass in unserer vernetzten Welt selbst die kleinsten Codeänderungen massive globale Auswirkungen haben können. Ob Sie eine einfache Website bauen oder kritische Infrastruktur verwalten, das Verständnis von React-Grundlagen und die Implementierung ordnungsgemäßer Engineering-Prozesse ist nicht nur gute Praxis – es ist essentiell für die Internet-Stabilität.
Das nächste Mal, wenn Sie einen useEffect Hook schreiben, denken Sie daran: Cloudflares Ingenieure überprüfen wahrscheinlich auch ihre Dependency-Arrays doppelt.