Die lokale Entwicklung mit Cloudflare Workers ist eine der flüssigsten Erfahrungen, die serverlose Lösungen heute bieten können. Die wrangler dev steigen in Sekundenschnelle, die Protokolle erscheinen im Terminal und alles scheint genau so zu funktionieren, wie Sie es erwarten. Das Problem besteht darin, dass dieser Komfort grundlegende Unterschiede verdeckt, die nur sichtbar werden, wenn der Code wirklich den Rand erreicht. Viele Teams stellen spät fest, dass console.log in der Produktion nirgendwohin führt, es sei denn, es gibt jemanden, der aktiv wrangler tail ausführt, dass das Puffern einer 50-MB-Antwort Isolate stillschweigend tötet und dass der Handler, der 15 Abfragen in D1 plus 10 Lesevorgänge in KV ausführt, eine Zeitbombe für das Subrequest-Limit darstellt.
Was passiert mit Ihren Protokollen in der Produktion?
Vor Ort wird wrangler dev alle console.log in Echtzeit auf dem Terminal angezeigt. In der Produktion verfügen die V8-Isolate von Cloudflare nicht über einen dauerhaften Prozess zur Erfassung dieser Ausgabe – jeder Aufruf wird isoliert ausgeführt, ausgeführt und verschwindet. Auf Protokolle kann nur über wrangler tail zugegriffen werden, wodurch eine Streaming-Sitzung mit Arbeitern in der Produktion geöffnet wird und Anforderungsmetadaten, console.log-Ausgabe, nicht abgefangene Ausnahmen und CPU-Dauer weitergeleitet werden.
Der kritische Punkt: Diese Sitzung bleibt nicht bestehen. Wenn beim Auftreten eines Fehlers kein Tailing erfolgt, geht das Protokoll verloren. Für die Aufbewahrung ist Logpush die Lösung – das Protokolle für 0,05 $ pro Million Zeilen für R2 nach R2, S3, Datadog oder Splunk exportiert. Aber Logpush funktioniert mit den strukturierten Feldern, die die Worker-Laufzeit ausgibt, nicht mit console.log freiem Text. Die praktische Konsequenz ist, dass nützliche Protokolle in der Produktion von Anfang an strukturiert werden müssen: JSON mit Feldern wie requestId, duration, statusCode, error – Felder, die sowohl wrangler tail filtern als auch Logpush originalgetreu exportieren kann.
Das funktionierende Muster besteht darin, zu Beginn des Projekts einen minimalen Protokollierungs-Wrapper zu erstellen, bevor Sie ihn benötigen. Etwas, das in JSON serialisiert und in console.log schreibt, wobei ein Feld level info von error unterscheidet. Wenn Logpush eintrifft, stehen diese Felder für Filter und Warnungen auf dem Ziel zur Verfügung.
Speicher: 128 MB sind kleiner als es scheint
Die 128-MB-Grenze pro Isolat umfasst das unkomprimierte Skript in V8, alle Modulschließungen und den gesamten Heap des aktuellen Aufrufs. Es sind nicht 128 MB für „Ihre Daten“, sondern 128 MB für alles, einschließlich der Laufzeit selbst.
Der häufigste Fehler besteht darin, in großen Antworten response.arrayBuffer() zu nennen. Eine 30 MB große Datei, die von einem anderen Dienst heruntergeladen und verarbeitet und weitergeleitet werden soll, belegt sofort 30 MB Heap. Wenn durch die Verarbeitung weitere Zwischenzuweisungen erstellt werden, überschreitet das Isolat 128 MB und wird beendet – keine abfangbare Ausnahme, keine Antwort an den Client, nur ein 1101-Fehler von außen.
Die Lösung besteht darin, response.body als ReadableStream zu verwenden und über TransformStream zu verarbeiten. Anstatt zu puffern und zu transformieren, erstellen Sie eine Pipeline, in der Chunks fließen: vom Upstream gelesen, während der Übertragung transformiert, in die Antwort geschrieben, ohne dass jemals Ganzzahlen im Speicher vorhanden sind. Bei Antworten, die größer als 1 MB sind, sollte von Streaming ausgegangen werden. Pufferung sollte eine explizite und begründete Wahl sein, nicht der Standardpfad.
Die gleiche Argumentation gilt für Uploads. Der maximale Anforderungstext beträgt 100 MB, aber request.arrayBuffer() versucht, alles auf einmal zuzuweisen. Bei großen Uploads muss die Verarbeitung ebenfalls im Stream erfolgen, oder die Datei muss über put(), das ReadableStream akzeptiert, direkt an R2 gesendet werden.
Unteranfragen: das Limit, das zum ungünstigsten Zeitpunkt erscheint
Jeder fetch(), jede Operation auf KV, jede Abfrage auf D1, jede Lesung auf R2 zählt als Unteranfrage. Beim kostenpflichtigen Plan liegt das Limit bei 1000 pro Aufruf. Kostenlos, 50.
Ein Handler, der vernünftig erscheint – ruft den Benutzer in D1 ab, liest seine Präferenzen in KV, ruft das Dokument aus R2 ab, ruft eine externe API auf, speichert das Ergebnis in D1 – ist bereits 5 Unteranfragen auf dem glücklichen Weg. Wenn dieser Handler in eine Schleife gerät, weil er eine Liste von Elementen verarbeitet, steigt der Zähler schnell an. Fünfzig Elemente mit jeweils zwei Vorgängen liegen bereits nahe bei 100. Ein Fehler, der N+1-Abfragen in D1 durchführt – die Suche nach jedem untergeordneten Datensatz einzeln statt mit einem JOIN – kann vor dem Ende einer einzelnen komplexen Anfrage leicht über 1000 hinauslaufen.
Der Fehler beim Erreichen des Grenzwerts ist nicht offensichtlich: Der Worker erhält bei der Unteranforderung, die den Grenzwert überschreitet, einen Netzwerkfehler, der mit einer Instabilität des Netzwerks oder des Downstream-Dienstes verwechselt werden kann. Für eine korrekte Diagnose müssen die Ausnahmeprotokolle über wrangler tail angezeigt und mit dem Handler-Aufrufmuster korreliert werden.
Abhilfe: Verwenden Sie db.batch() in D1, um mehrere Abfragen in einer einzigen Unteranfrage zu gruppieren. KV-Konfigurationen einmal bei der Modulinitialisierung lesen und im globalen Bereich zwischenspeichern – das Isolat kann zwischen Anforderungen im selben PoP wiederverwendet werden, und das KV-Lesen, das beim ersten Aufruf erfolgte, muss bei nachfolgenden Aufrufen nicht wiederholt werden, solange das Isolat lebt.
Geheimnisse, Umgebungen und die wrangler.toml, die in das Repository geht
In wrangler.toml unter [vars] deklarierte Variablen sind Klartext in der Konfigurationsdatei, die normalerweise in das Repository gelangt. Für jeden sensiblen Wert – API-Schlüssel, Bank-Tokens, Webhook-Geheimnisse – ist die einzig richtige Option „Workers Secrets“, die in wrangler.toml als [secrets] deklariert und über wrangler secret put gespeichert wird. Der Wert wird im Ruhezustand verschlüsselt und zur Laufzeit als Eigenschaft von env eingefügt, ohne in Build-Protokollen oder Artefakten zu erscheinen.
Die wrangler.toml eines Dienstes, der in Produktion geht, muss explizite Umgebungen haben: [env.staging] und [env.production] mit ihren eigenen separaten Bindungen, Routen und Geheimnissen. Das Mischen von Staging und Produktion im selben Bindungssatz ist ein Unfall, der nur darauf wartet, passiert – insbesondere, wenn D1 und KV über echte Daten in der Produktion und Testdaten im Staging verfügen. Durch die Trennung von Umgebungen in wrangler.toml kann die CI-Pipeline außerdem automatisch im Staging bereitgestellt werden und erfordert eine manuelle Genehmigung für die Produktion, ohne dass zusätzliche Logik im Bereitstellungsskript erforderlich ist.
So sieht ein minimaler Produktionsaufbau aus
Ein produktionsbereiter wrangler.toml verweist explizit auf compatibility_date (um keine Breaking Changes von der Laufzeit ohne Warnung zu erhalten), definiert [observability] mit enabled = true, um grundlegende Metriken auf dem Dashboard verfügbar zu machen, und trennt [env.staging] von [env.production] mit unterschiedlichen Routen. Secrets werden nach Namen ohne Wert aufgelistet – der Wert existiert nur in Cloudflare, niemals im Repository.
Der Haupthandler verfügt über einen try/catch auf der höchsten Ebene, der alle nicht behandelten Ausnahmen abfängt, sie als JSON mit der Struktur console.error protokolliert und eine HTTP 500-Antwort mit einem nachverfolgbaren requestId zurückgibt. Ohne diese Grenze könnte eine unerwartete Ausnahme eine 200 mit abgeschnittenem Text an den Client zurückgeben, während der eigentliche Fehler nur im Ende erscheint – und nur, wenn jemand hinschaut.
Lesen Sie auch
- Cloudflare Workers: Praktischer Leitfaden für serverloses Edge Computing
- D1 in der Produktion: Leistung, Grenzen und was sich nicht alleine skalieren lässt
- WebAssembly am Rande: Warum ein schneller und isolierter Start wichtig ist
- Worker: Debugging, Protokolle und Workers Tail – Beobachtbarkeit am Edge ohne Protokollserver
- Arbeiter: CPU- und Speichergrenzen – was in der Dokumentation nicht gut erklärt wird
- Entwicklung serverloser Anwendungen mit AWS Lambda und Cloudflare Workers im Jahr 2025
