WordPress Cronjobs fallen unter Last aus, wenn Seitenaufrufe den internen Scheduler blockieren, Caches Anfragen abfangen oder Hosting-Limits lange Tasks kappen. Ich zeige Ursachen, Folgen und konkrete Lösungen, damit Aufgaben wie Updates, Backups und geplante Beiträge zuverlässig laufen.
Zentrale Punkte
Zum Start fasse ich die wichtigsten Aspekte kurz und klar zusammen, bevor ich tiefer einsteige und konkrete Schritte erläutere, die ich produktiv einsetze. Problemerkennung und Ursachen stehen dabei im Fokus.
- Mechanik: WP-Cron triggert bei Seitenaufrufen statt über System-Cron.
- Last: Hoher Traffic und „wordpress cron load“ erzeugen Timeouts.
- Caching: Vollständiges CDN-Caching stoppt Cron-Ausführung.
- Limits: PHP-Timeouts und Ressourcen-Budgets brechen Tasks ab.
- Abhilfe: Server-Cron, saubere Intervalle, Logging und Tuning.
WP-Cron kurz erklärt: Seitenaufruf statt Systemdienst
Ich starte mit der Grundidee: WordPress prüft bei jedem Seitenaufruf, ob geplante Tasks fällig sind, und feuert sie per interner HTTP-Anfrage an wp-cron.php. Dieser Ansatz kompensiert fehlenden Zugriff auf echte Server-Crons, erzeugt aber Abhängigkeit vom Traffic. Erreicht eine Seite kaum Besucher, laufen Tasks verspätet oder gar nicht. Bedient ein CDN jede Anfrage aus dem Cache, lädt PHP nicht, und WP-Cron bleibt stumm. Das erklärt, warum geplante Veröffentlichungen, E-Mail-Jobs oder Backups auf manchen Installationen unzuverlässig wirken. Je mehr Plugins zusätzliche Aufgaben registrieren, desto dichter wird die Queue und desto anfälliger wird die Ausführung.
Warum Last Cronjobs kippen lässt
Steigt der Besucherstrom, steigen auch die Cron-Prüfungen und damit die Serverlast. Mehr gleichzeitige Anfragen konkurrieren um PHP-Worker, I/O und Datenbank, wodurch Cron-Aufrufe in Timeouts rutschen. Latenzen häufen sich, Aufgaben blockieren einander, und lange Tasks verlassen das Zeitfenster. In produktiven Setups adressiere ich das konsequent, da WP-Cron auf Produktivseiten oft der Auslöser für zähe Reaktionszeiten ist. Unter hoher Last korrelieren Slowdowns direkt mit übermäßig frequentierten Cron-Triggern. Zusätzlich verschärfen schlecht geschriebene Tasks die Situation, weil sie Datenbank-Scans starten, die noch mehr Ressourcen binden.
Hosting-Limits und deren Folgen
Viele Hoster setzen ein PHP-Timeout von 30–60 Sekunden; überschreitet ein Task diese Marke, beendet das System ihn hart. Das trifft Migrationsjobs, große Exporte, Bildverarbeitung oder Massenmails. Ähnlich wirken memory_limit, Prozess-Limits und Rate-Limits bei HTTP-Loopbacks. Kommt dann noch geringer Traffic hinzu, sammeln sich fällige Events an und laufen verspätet oder gar nicht. Ich prüfe deshalb zuerst Limits und Logs, bevor ich an der Anwendung drehe. So erkenne ich, ob die Umgebung Engpässe verursacht oder ob einzelne Tasks ineffizient sind.
Schnell-Check: Ursachen, Symptome, Lösungen
Die folgende Übersicht hilft mir, Fehlerbilder strukturiert zu trennen und zielgerichtet zu handeln, statt planlos zu experimentieren. Jede Zeile zeigt eine Ursache, ein sichtbares Symptom und eine Sofortmaßnahme.
| Ursache | Typisches Symptom | Sofortmaßnahme |
|---|---|---|
| CDN/Reversed Proxy bedient 100% aus Cache | Geplante Beiträge erscheinen verspätet | WP-Cron entkoppeln, echten Server-Cron setzen |
| PHP-Timeout (30–60 s) | Abgebrochene Backups/Exporte | Timeout erhöhen, Task in kleinere Batches teilen |
| Zu viele Cron-Events | Spürbare Latenzen bei Peak-Traffic | Intervalle strecken, unnötige Events entfernen |
| Ineffiziente SQL-Abfragen | Datenbankauslastung steigt sprunghaft | Indexe setzen, SELECTs verschlanken, Caching |
| Low-Traffic-Website | Stundenlange Verzögerungen | System-Cron alle 15–60 Minuten ausführen |
Ich ergänze den Check mit realen Metriken aus Logs und Monitoring, um Annahmen zu verifizieren und die Ursache klar zu belegen. Die Tabelle ersetzt keine Messung, sie kanalisiert sie. Erst wenn ich weiß, ob Timeout, Cache oder Datenbank limitieren, setze ich die passende Maßnahme an. Danach teste ich wiederholt und prüfe, ob Folgeeffekte entstehen. So halte ich den Aufwand gering und löse das Problem nachhaltig.
Best Practices: Von WP-Cron zu Server-Cron
Ich deaktiviere zunächst den seitenbasierten Trigger mit DISABLE_WP_CRON in der wp-config.php: define(‚DISABLE_WP_CRON‘, true);. Danach richte ich einen echten System-Cron ein, der wp-cron.php zyklisch aufruft (z. B. per curl alle 5 Minuten bei starkem Traffic, stündlich bei Low-Traffic). Damit entkopple ich Ausführungen vom Besucherstrom und glätte die Last. Parallel limitiere ich gleichzeitige Aufrufe, damit keine Cron-Stürme entstehen. Wenn ich Spitzen erwarte, erhöhe ich PHP-Worker und passe Timeouts an. Gerade bei schwankendem Traffic reduziere ich so ungleichmäßige CPU-Last und verhindere Kettenreaktionen.
Intervalle, Task-Design und Datenbank
Ich prüfe jedes Event auf sein Intervall und strecke Frequenzen, wo immer es vertretbar ist. Statt jede Minute scanne ich stündlich oder täglich, wenn die Aufgabe keinen Echtzeitwert braucht. Lange Jobs teile ich in kleine Batches, die innerhalb des PHP-Timeouts sicher durchlaufen. Bei Datenbankzugriffen setze ich Indexe, reduziere Spalten und verzichte auf Voll-Scans. Häufige Daten cachte ich, um Wiederholungen abzufangen und die Datenbank von unnötiger Arbeit zu entlasten. So sinken Laufzeiten, und Cron-Ausführungen bleiben kalkulierbar.
Diagnose in der Praxis: Sichtbarkeit schaffen
Bevor ich umbaue, will ich verlässliche Diagnosedaten. Ich beginne mit der WordPress-Site-Health-Anzeige und aktiviere Logging (WP_DEBUG_LOG), um PHP-Fehler bei Cron-Aufrufen sichtbar zu machen. Dann liste ich fällige und geplante Events sowie ihre Laufzeiten. In produktiven Workflows nutze ich dazu wiederholbare Schritte:
- Fällige Events per WP-CLI anstoßen: wp cron event run –due-now
- Geplante Events auflisten: wp cron event list
- Eigene Messpunkte setzen: Start-/Endzeit im Task loggen, inklusive Peak Memory
- Datenbankseite prüfen: Lange SELECTs identifizieren und nötige Indexe hinzufügen
Zeigt Site-Health „Verzögerte Cron-Ausführung“, werte ich Zugriffslogs auf wp-cron.php, Response-Codes und Dauer aus. 429/503 deuten auf Rate- oder Ressourcelimits, 401/403 auf Blockaden durch Auth, Firewall oder WAF. Ich überprüfe, ob Loopback-Requests intern erlaubt sind und ob der Hostname korrekt auflöst. Darüber hinaus schaue ich in die Option „cron“ der wp_options, um Größe und Alter der Queue zu beurteilen und Funktions-Hooks zu identifizieren, die wiederholt scheitern.
Robuste Server-Cron-Konfiguration: HTTP, WP-CLI und Sperren
Für produktive Umgebungen ziehe ich einen Server-Cron via WP-CLI einem puren HTTP-Aufruf vor, weil ich damit PHP direkt starte und weniger von Webserver/Proxy abhänge. Beispielhafte Varianten, die sich bewährt haben:
- HTTP variabel, mit Zeitbudget und Stillhaltung: curl -sS https://domain.tld/wp-cron.php?doing_wp_cron=1 –max-time 55 –connect-timeout 5 >/dev/null
- WP-CLI direkt: cd /pfad/zur/installation && /usr/bin/wp cron event run –due-now –quiet
- Überlappungen vermeiden: flock -n /tmp/wp-cron.lock -c „/usr/bin/wp cron event run –due-now –quiet“
- Ressourcen gezielt anheben: php -d memory_limit=512M -d max_execution_time=300 wp-cli.phar cron event run –due-now
Mit flock verhindere ich Parallelstarts, die sonst zu doppelten Ausführungen und konkurrierenden Datenbankzugriffen führen. Bei mehreren Instanzen (z. B. Blue/Green, Container) lasse ich nur einen Host den Cron ausführen und deaktiviere ihn auf den übrigen. So vermeide ich Race Conditions in der Queue.
Loopbacks, Auth und Firewalls: typische Blockaden
Hängen Cronjobs in „pending“, blockiert oft der interne Loopback. Ich prüfe, ob Basic-Auth, IP-Restriktionen oder eine WAF Anfragen an wp-cron.php unterbindet. In gesicherten Staging-Setups schließe ich wp-cron.php von der Authentifizierung aus oder erlaube Loopbacks als Ausnahme. Falls externe HTTP-Aufrufe restriktiert sind, stelle ich sicher, dass die eigene Domain nicht auf der Blockliste steht. Als Notnagel kann ALTERNATE_WP_CRON kurzfristig helfen, dafür setze ich es nur temporär ein und entferne es wieder, sobald ein sauberer Server-Cron aktiv ist.
Überlappungen und Idempotenz: Aufgaben sicher machen
Viele Probleme entstehen durch gleichzeitige Ausführungen derselben Aufgabe. Ich baue daher per-Task-Sperren ein (z. B. via Transient/Option), prüfe vor Start, ob bereits ein Lauf aktiv ist, und beende den zweiten Aufruf frühzeitig. Gleichzeitig mache ich Aufgaben idempotent: Wird ein Step zweimal gestartet, führt er nicht zu doppelten E-Mails, Dateien oder DB-Einträgen. Bei Batch-Jobs speichere ich Offsets/Marker, um Fortsetzungen sauber zu steuern und Wiederholungen abzufangen. Das reduziert Folgeschäden, wenn ein Cronlauf unerwartet abbricht und später neu startet.
Skalierung: Multiserver, Container und Multisite
In verteilten Umgebungen betreibe ich genau einen Cron-Runner. Das kann ein separater Worker-Container oder ein fester Knoten sein, der per WP-CLI alle fälligen Events anstößt. Shared-Dateisysteme oder verteilte Caches helfen, Status und Sperren zwischen Instanzen konsistent zu halten. In Multisite-Setups prüfe ich, ob Cron für jedes Subsite-Netz sauber geplant ist und ob Netzwerkevents nicht unkontrolliert die globale Queue fluten. Zudem stelle ich sicher, dass die Zeitzonen pro Site korrekt sind, damit Veröffentlichungen und Zeitfenster stimmen.
Zeiten und Zeitzonen: „Missed Schedule“ vermeiden
Ein unterschätzter Faktor sind Zeitzonen und Sommerzeitwechsel. WordPress plant Beiträge in der Site-Zeitzone, während Server oft in UTC laufen. Ich gleiche beides ab, prüfe bei Deployments die Zeitzonen-Einstellungen und berücksichtige Zeitumstellungen im Redaktionsplan. Tritt „Missed schedule“ auf, kontrolliere ich, ob die Cronqueue überfüllt ist, ob Publikations-hooks fehlschlagen oder ob die Serverzeit driftet. Ein anschließendes „wp cron event run –due-now“ entlädt die Warteschlange, während ich die eigentliche Ursache (Cache, Timeout, falsche Zeitzone) behebe.
Entwicklung, Staging und Deployments
In Staging-Umgebungen deaktiviere ich produktive Tasks (E-Mails, Exporte, Webhooks), damit keine unbeabsichtigten Aktionen ausgelöst werden. Ich setze DISABLE_WP_CRON auf true und betreibe einen eigenen Test-Cron mit langen Intervallen. Vor Go-Live leere ich die Queue, führe die kritischen Tasks einmal manuell aus und beobachte Logs engmaschig. Nach Deployments triggert ein gezielter „due-now“-Lauf die neuen Hooks, bevor Caches wieder aggressiv werden. So verhindere ich Überraschungen und halte die Einführungsphase ruhig.
Fehlerbehandlung, Backoff und Wiederholungen
Ausfälle passieren. Ich plane sie ein, indem ich Retries mit Backoff nutze: Erst nach kurzer Zeit erneut versuchen, dann mit wachsendem Abstand. Fehlgeschlagene Schritte dokumentiere ich mit klaren Codes und Kontext (Input, Dauer, Speicher, SQL, HTTP-Code). Nach N Fehlversuchen markieren ich das Event als „stuck“ und informiere mich per Alert. Diese Trennung verhindert Endlosschleifen und gibt mir Zeit, die eigentliche Ursache zu beheben, ohne die Queue zu verstopfen.
Werkzeuge: WP Crontrol und Action Scheduler
Zur täglichen Kontrolle nutze ich WP Crontrol, um Events direkt in WordPress zu sehen, zu pausieren oder neu zu planen. Ich erkenne damit hängende Hooks, doppelte Einträge oder fehlerhafte Intervalle. Für große Prozesse setze ich Action Scheduler ein, der Aufgaben in kleine Aktionen aufteilt und sauber protokolliert. Fällt eine Aktion aus, starte ich sie gezielt neu, ohne die gesamte Kette zu gefährden. Das mindert Spitzen, weil ich nicht einen Monolithen durchdrücke, sondern Teilaufgaben taktisch verteile. So bleiben Deployments und Wartungsfenster berechenbar.
Shared Hosting, Caching und CDNs
In Shared-Umgebungen kollidieren Cron-Aufrufe schnell mit Limits, die ich nicht direkt steuere. Greifen dann CDN und Full-Page-Cache, triggert kein einziger Seitenaufruf WP-Cron. Ich umgehe das mit einem System-Cron und sorge dafür, dass Loopback-Anfragen erreichbar sind. Wo Cron nicht zuverlässig feuert, prüfe ich Netzwerkrichtlinien, Basic-Auth und Firewalls. Ein Test mit direktem curl-Aufruf zeigt, ob Anfragen technisch ankommen. Für Hintergründe und Alternativen verweise ich auf Cronjobs im Shared Hosting, weil dort typische Stolpersteine kompakt beschrieben sind.
Monitoring und Wartung im Alltag
Ich behalte die Site-Health-Hinweise im Blick, denn WordPress meldet verspätete Cron-Ausführungen sichtbar. Zusätzlich schreibe ich Logs, um Dauer, Fehler und Wiederholungen statistisch auszuwerten. Das deckt Anomalien auf, die im Tagesgeschäft sonst untergehen. Veraltete oder dauerhaft fehlschlagende Events lösche oder resette ich, um die Queue schlank zu halten. Alerts per Mail oder Slack informieren mich, wenn ein Job mehrfach scheitert. So greife ich ein, bevor Folgen wie verpasste Updates oder nicht versendete Mails Schaden anrichten.
Abschluss: Meine Vorgehensweise in Kurzform
Zuerst entkopple ich Cron von Seitenaufrufen, stelle einen Server-Cron ein und prüfe Erreichbarkeit per curl. Danach optimiere ich Intervalle, teile lange Tasks in Batches und reduziere Datenbanklast. Ich setze Logging auf, schaue mir Fehlerpfade an und passe Limits so an, dass kein Task am Timeout zerschellt. Bei Bedarf setze ich Action Scheduler ein, weil er lange Abläufe zuverlässig in steuerbare Teile zerlegt. Anschließend messe ich Wirkung und verschlanke die Cron-Liste, bis die Queue sauber bleibt. So laufen geplante Aufgaben verlässlich, selbst wenn die Last steigt oder Caches aggressiv arbeiten.


