Cronjob-Intervalle steuern direkt, wie stark CPU, RAM und I/O arbeiten und wie gleichmäßig Last über den Tag verteilt bleibt. Setze Intervalle nicht zu eng, sonst steigen parallele Läufe, es entstehen Überlappungen und die Serverlast schaukelt sich hoch.
Zentrale Punkte
Ich fasse die wichtigsten Hebel kurz zusammen und ordne sie im weiteren Text praktisch ein.
- Frequenz bestimmt Ausführungszahl und parallele Läufe
- Timing glättet Lastspitzen in Off-Peak-Fenstern
- Optimierung der Skripte senkt Ressourcenbedarf
- Monitoring deckt Engpässe und Jitter auf
- Alternativen wie Queues oder externer Cron entlasten
Ich priorisiere Jobs nach Wirkung auf Nutzer und wähle für schwere Tasks weite Abstände. Danach verteile ich Starts über die Stunde, um nicht alles auf Minute 0 zu legen und so Kollisionen zu vermeiden. Laufzeiten messe ich real auf dem Server, nicht lokal, damit CPU-Drosselung sichtbar wird. Bleiben Peaks, setze ich Limits und verschiebe die Jobs in ruhigere Zeitfenster. So bringe ich Kontinuität in die Ausführung und halte Reserven frei.
Wie enge Intervalle Lastspitzen erzeugen
Starte ich einen Job häufig, steigt die Ausführungszahl linear, während I/O und CPU sich nicht linear erholen. Läuft ein Task 3 Minuten und startet alle 5 Minuten, bleiben nur 2 Minuten Puffer – kleine Verzögerungen führen sofort zu Überlappungen. Treffen dann mehrere Cronjobs aufeinander, konkurrieren sie um CPU-Zeit, der I/O-Queue wächst, und Response-Zeiten klettern. In Shared-Umgebungen kommen Laufzeitlimits und Prozessgrenzen dazu, was die Warteschlange noch verlängert. So entsteht eine Kettenreaktion: mehr Wartezeit, mehr parallele Prozesse, mehr Last.
Ich rechne mir vorab eine grobe Parallelität: Ausführungsdauer geteilt durch Intervall ergibt die erwartete Überlappung. Liegt der Wert über 0,7, plane ich breiter oder verschiebe in Off-Peak-Stunden. Schon der Start-Overhead eines Cron-Aufrufs ist spürbar, wenn er dutzendfach pro Stunde anliegt. Bei datenintensiven Jobs zählt außerdem das Cache-Verhalten: kalte Caches bei eng getakteten Läufen erhöhen I/O, weil der Kernel selten dieselben Seiten warm hält. Deshalb setze ich lieber seltener laufende, aber effizientere Durchläufe.
Frequenzklassen sinnvoll wählen
Für Echtzeit-Nähe nutze ich nur dann einen 1–5-Minuten-Takt, wenn der Job leicht ist und ich harte Reaktionszeiten brauche. Wartung, Cleanup und Reportings laufen bei mir im 15–60-Minuten-Raster, das reduziert die Ausführungen auf überschaubare 24–96 pro Tag und hält die Auslastung gleichmäßiger. Backups, Log-Rotation oder Bildstapel lege ich stündlich oder täglich, weil die Datenmenge hoch ist und Kompression I/O bindet. Wichtig ist, dass leichte Tasks die Minute 0 nicht teilen: ich verteile Starts auf 5, 17, 29, 41, damit Cluster vermieden werden. Außerdem setze ich für sehr lange Prozesse ein eigenes Fenster, damit sie nicht in Shop-Peaks hineinragen.
Für Shops, APIs und CMS nutze ich eine Mischung: Inventarabgleich und Cache-Warmups moderat, rechenintensive Indizes nachts. Das senkt Stottern bei Live-Traffic und schützt Transaktionen. Drehe ich Frequenzen hoch, sichere ich erst die Task-Laufzeit ab, sonst multipliziere ich nur die Last. Bei kurzen Jobs prüfe ich, ob sich Ereignis-Trigger eignen, etwa Webhooks statt starrem Cron. So bleibt die Taktung schlank und zielgerichtet.
Hosting-Umgebungen im Vergleich
In gemeinsam genutzten Umgebungen schlagen Limits sofort auf Jitter durch: Intervall ab 15 Minuten, kurze Laufzeiten, begrenzte Prozesse. Ich plane dort breitere Abstände, weil Threads sonst aufeinander warten und Cronläufe nach hinten rutschen. Auf einem VPS oder eigenen Server kann ich sekundengenaue Startzeiten, dedizierte CPU/RAM und faire Prioritäten setzen. Dann setze ich cgroups, nice/ionice und getrennte Queues ein, damit wichtige Tasks Vorrang bekommen. Externe Cron-Dienste helfen, wenn der Applikationsserver Lastspitzen abschütteln muss.
| Hosting-Typ | Typische Intervalle | Ressourcen | Laufzeitlimits | Monitoring |
|---|---|---|---|---|
| Shared Hosting | ab 15 Minuten | geteilt | kurz (z. B. 300 s) | eingeschränkt |
| VPS | sekündlich möglich | dediziert | konfigurierbar | vollständig |
| Externer Cron | minütlich | unabhängig | keine | mit Alerts |
Ich entscheide nach Bedarf: Brauche ich harte Zeitfenster und Kontrolle, nutze ich VPS oder externen Cron. Möchte ich Kosten sparen, halte ich Shared-Jobs besonders schlank und großzügig getaktet. Für Mischszenarien kombiniere ich beide Welten: Trigger von extern, Verarbeitung intern in gemäßigten Blöcken. Damit entkopple ich Benutzer-Traffic und Batchläufe sauber. Die Wahl des Setups prägt am Ende direkt die Planung der Intervalle.
WP-Cron entkoppeln und richtig triggern
WP-Cron hängt an Seitenaufrufen, prüft bei jedem Hit überfällige Jobs und erzeugt unnötige Spitzen. Ich deaktiviere den internen Trigger mit define('DISABLE_WP_CRON', true); und rufe wp-cron.php via echten Cron alle 15 Minuten auf. So laufen Jobs zeitgesteuert, unabhängig von Besuchern, und die Last verteilt sich sauberer. Bei sehr aktiven Sites setze ich 5–10 Minuten, bei kleineren 15–30 Minuten, stets mit Blick auf Laufzeiten. Hintergründe zu ungleichmäßiger CPU-Last durch WP-Cron erläutere ich hier: CPU-Last durch WP-Cron.
Für parallele Läufe setze ich Lockfiles: flock verhindert, dass ein neuer Run startet, solange der alte noch arbeitet. Das schützt vor Überlappungen, besonders bei Importen und Indizes. Zusätzlich begrenze ich PHP mit memory_limit und max_execution_time, damit sich Ausreißer nicht festfressen. Mit ionice senke ich I/O-Priorität großer Kopiervorgänge, damit Frontend-Anfragen zügig bleiben. Diese kleinen Stellschrauben wirken stärker als die reine Intervalländerung, weil sie die Konflikte minimieren.
Idempotenz und Wiederholbarkeit
Ich gestalte Cronjobs idempotent, damit Wiederholungen keinen Schaden anrichten. Schreibende Jobs versiehe ich mit Idempotency-Keys oder eindeutigen Constraints (z. B. auf Basis einer Quell-ID), damit doppelte Läufe keine Duplikate erzeugen. Längere Prozesse bekommen Checkpoints: ein Persistenzpunkt pro Batch (z. B. letzte verarbeitete ID/Datum), damit Restarts dort anknüpfen und nicht von vorn beginnen. Bei mehrstufigen Pipelines nutze ich kompensierende Schritte (z. B. Revert-Buchungen), wenn ein späterer Schritt fehlschlägt. So bleiben Retrys sicher und ich muss Intervalle nicht künstlich hochdrehen, nur um Fehler zu vermeiden.
Zeitzonen, NTP und Zeitumstellung
Ich denke Cron immer in UTC, um Verschiebungen durch Sommer-/Winterzeit zu vermeiden. Muss lokalzeitbezogen geplant werden, dokumentiere ich, dass die Stunde der Umstellung doppelt oder gar nicht ausgeführt wird. Die Systemuhr halte ich mit NTP/chrony synchron – Clock Skew zwischen Hosts führt sonst zu ungewollter Parallelität, verpassten Fenstern oder Ratenlimit-Verstößen bei externen APIs. In globalen Setups lege ich pro Region eigene Slots an und plane Zeitfenster gegenläufig, damit sich Peaks nicht addieren.
Cron, systemd-timers und anacron
Neben klassischem Cron setze ich systemd-timers ein, wenn ich feinere Steuerung brauche. Vorteile sind RandomizedDelaySec (Jitter ohne eigene Sleeps), AccuracySec (Startfenster) und Persistent=true (Nachholen verpasster Läufe). Für Laptops oder selten laufende Server hilft anacron, damit tägliche Jobs trotz Auszeiten sicher nachgeholt werden. Einmalige Aufgaben schiebe ich mit at, statt sie in Cron zu belassen.
Ein minimales Beispiel mit Ressourcenlimits und Locking:
[Unit]
Description=Maintenance Job
[Service]
Type=oneshot
ExecStart=/usr/bin/flock -n /var/lock/maint.lock
/usr/bin/nice -n 10 /usr/bin/ionice -c2 -n7 /usr/local/bin/maint.sh
MemoryMax=512M
CPUWeight=20
IOSchedulingClass=best-effort
IOSchedulingPriority=7
[Install]
WantedBy=multi-user.target
[Unit]
Description=Maintenance Timer
[Timer]
OnCalendar=*:07,37
RandomizedDelaySec=30
Persistent=true
AccuracySec=1min
[Install]
WantedBy=timers.target
Jitter, Rate-Limits und faire Nutzung
Ich streue Starts bewusst mit Jitter, um Thundering-Herd-Effekte zu vermeiden. Im klassischen Cron erledigt ein kurzes sleep $((RANDOM%30)) die Entzerrung, unter systemd nehme ich RandomizedDelaySec. Greifen Jobs auf externe APIs zu, respektiere ich Quoten und baue Client-seitiges Rate-Limiting ein. So bleiben Läufe konstant, statt im Fehlerfall Retrystürme zu erzeugen, die erneut Limits reißen.
Fehlerhandling, Timeouts und Backoff
Jeder Job bekommt klare Timeouts und saubere Exit-Codes. Retrys versehe ich mit Exponential Backoff und einer Obergrenze, plus Dead-Letter-Logik für hartnäckige Fälle. Kritische Pfade schütze ich mit Circuit Breakern: Schlagen viele Aufrufe hintereinander fehl, pausiere ich, statt aggressiv weiter zu laufen. In den Logs notiere ich Ursache, Betroffene und nächste Aktion – nicht nur “failed”. Das verringert Blindflüge und verhindert, dass ich Intervalle aus Unsicherheit zu weit dehne.
Konfigurationshygiene und Sicherheit
Ich schreibe Crontabs explizit: absolute Pfade, definierte PATH-, LANG– und UMASK-Variablen, eindeutige MAILTO oder Log-Ziele. Jobs laufen unter least privilege mit eigenen Unix-Usern statt als root. Zugangsdaten halte ich aus der Crontab heraus und lade sie aus sicheren .env-Dateien oder dem Secret-Store. Dateirechte und Netzwerkzugriffe begrenze ich per Firewall und ulimit, damit Fehlkonfigurationen nicht das System öffnen. Eine kurze Crontab-Headersektion verhindert Überraschungen:
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
LANG=C.UTF-8
UMASK=027
[email protected]
Skalierung über mehrere Hosts
In Clustern achte ich darauf, dass nur ein Host singleton-Jobs ausführt. Das löse ich mit Datenbank-Advisory Locks, verteiltem Locking (z. B. via Redis) oder Host-Pinning. Alternativ wähle ich ein Leader-Election-Verfahren und lasse nur den Leader starten. Für horizontale Skalierung zerlege ich Arbeit in idempotente, kleine Einheiten, die Worker parallel abholen. So kann ich Kapazität fein erhöhen, ohne die Cronfrequenz zu ändern.
Praxisnahe Beispiele
Ein klassischer, entschärfter Cron-Eintrag mit Logging, Locking und Priorisierung:
7,37 * * * * flock -n /var/lock/report.lock
nice -n 10 ionice -c2 -n7 /usr/local/bin/build_report.sh
>> /var/log/cron/build_report.log 2>&1
Für Jobs, die sich gegenseitig stören könnten, definiere ich Fenster und nutze einfache Guards:
MINUTE=$(date +%M)
if [[ "$MINUTE" -ge 0 && "$MINUTE" -le 10 ]]; then
exit 0 # kein Start im Backup-Fenster
fi
Und wenn ein Prozess nur bei leerem Backlog starten soll, prüfe ich zuerst die Queue-Größe und entscheide dann, ob sich der Lauf lohnt. So vermeide ich “Leerlauf”-Starts, die nur Overhead produzieren.
Kosten- und Energieeffizienz
Ich berücksichtige Kostenpfade: Kompression frisst CPU, spart aber Storage und Bandbreite; ein moderates zstd-Level kann günstiger sein als maximaler gzip-Druck. Große Exporte takte ich vor günstigen Off-Peak-Tarifen, um Strom- oder Cloud-Kosten zu senken. Egress-lastige Jobs fasse ich zusammen, damit ich Quoten besser plane. Wer Kapazität und Intervalle an Kosten koppelt, vermeidet sowohl Unter- als auch Überprovisionierung.
Testen, Stufen und Rollback
Änderungen an Cron behandle ich wie Code: Ich teste lokal mit den Ziel-Datenmengen, rolle in Stufen aus (ein Host, dann mehrere), markiere die Startfenster in den Metriken und behalte Fehlerquoten im Blick. Missfällt die Auswirkung (mehr Overlap, höhere Latenz), rolle ich zurück. Ein kleines Runbook hilft dem Team: Was tun bei Verzug, wie Lockfiles lösen, wann pausieren oder priorisieren? So bleiben Intervalle stabil, auch wenn das System sich verändert.
Queues und externer Cron als Entlastung
Wenn ein Job mehr Arbeit sieht als ein einzelner Lauf schafft, schiebe ich Aufgaben in eine Queue und lasse Worker kontinuierlich ziehen. So verteilt sich Rechenzeit besser, und ich setze die Cron-Frequenz nur noch zum Anstoßen oder Health-Check ein. Redis- oder Database-Queues mit Retry-Logik, Rate-Limits und Dead-Letter-Handling verhindern Staus. Ein externer Cron-Dienst kann URL-Trigger zuverlässig abfeuern, selbst wenn der Anwendungsserver knapp ist. Eine kurze Praxisübersicht findest du hier: asynchrone PHP-Tasks.
Ich dimensioniere Worker nach SLA, nicht nach Bauchgefühl: lieber konstante, niedrigere Parallelität als kurze Ausreißer. Bei Überlauf skaliere ich Worker temporär hoch und ziehe sie danach zurück. Retrys versehe ich mit Backoff, damit Fehlerwellen nicht alles blockieren. Sichtbarkeit schaffe ich mit Metriken pro Queue, etwa Durchsatz, Wartezeit und Fehlerrate. So behalte ich Kontrolle, ohne Cronintervalle künstlich zu drücken.
Shared Hosting: typische Stolpersteine
In geteilten Umgebungen bremst CPU-Drosselung Cronläufe oft unvorhersehbar aus, und kurze Intervalle verschärfen das. Ich stelle dann auf größere Abstände um und prüfe, ob ein externer Cron zuverlässig triggern kann. Für tieferen Einblick empfehle ich diesen Überblick zu Hintergründen und Alternativen: Cronjobs im Shared Hosting. Zusätzlich splitte ich schwere Arbeit in kleinere Pakete und plane sie außerhalb der Stoßzeiten. Wer wiederholt an Grenzen stößt, fährt mit einem kleinen VPS meist günstiger als mit Zeitverlust durch Limits.
Ich vermeide Web-basierten Cron im WordPress-Backend, wenn die Plattform wenig Traffic hat. Sonst stauen sich Jobs und starten später gebündelt. Ein klarer, externer Trigger oder echter Cron löst das. Dazu kommt Locking, damit keine Doppelstarts auftreten. So bleiben Response-Zeiten für Besucher verlässlich.
Monitoring und Messwerte: worauf ich schaue
Ich messe CPU, Load, I/O-Wait und RAM, dazu Laufzeiten pro Job und den Backlog über den Tag. Eine Heatmap der Startzeiten zeigt, wo sich Cronläufe ballen. Bei Apps prüfe ich gleichzeitig Latenzen, Fehlerquoten und Core Web Vitals. Kommt es zeitgleich mit Cronläufen zu Peaks, markiere ich die Zeitfenster. Danach passe ich Intervalle an, setze Prioritäten und prüfe, ob Locking sauber greift.
In Logs lasse ich mir Exit-Codes, Dauer, betroffene Tabellen oder Pfade ausgeben. Jeder Job bekommt eine maximale Laufzeit und ein klares Fehlerhandling. Misslingt ein Lauf, eskaliert ein Alarm statt stumm zu wiederholen. Für Backups protokolliere ich Größe, Durchsatz und Kompression, um I/O besser einschätzen zu können. Dieses Feedback macht die Planung erneuter Läufe deutlich treffsicherer.
Kapazität denken: kleine Formel, große Wirkung
Ich schätze Last mit einer einfachen Rechnung: erwartete Parallelität ≈ Laufzeit in Minuten geteilt durch Intervall. Wird der Wert größer als 1, plane ich Überlappungen fest ein und handle entsprechend. Dann erweitere ich Intervalle, kürze die Laufzeit oder verschiebe die Arbeit in Queues. Auf Storage-Ebene betrachte ich IOPS und Durchsatz, weil sie oft die wahren Grenzen setzen. Mit dieser Sicht skaliere ich weniger nach Gefühl und mehr nach Daten.
Noch hilfreicher wird die Formel mit Fehlerspielraum: Ich rechne plus 20–30 Prozent, um Jitter und Spikes zu puffern. Für saisonale Effekte halte ich alternative Pläne bereit, etwa für Sales oder Releases. So verhindere ich, dass geplante Intervalle bei Ereignissen plötzlich ungeeignet sind. Wer so denkt, baut automatische Skalierung für Worker und Prioritäten ein. Das hält die Antwortraten konsistent.
Langfristige Planung mit SLOs und Audits
Ich halte Serviceziele fest, zum Beispiel “95 Prozent der Cronjobs starten zur geplanten Zeit” oder “99 Prozent der Läufe bleiben unter 2 Minuten”. Diese SLOs lenken Entscheidungen über Intervalle, Prioritäten und Ressourcen. Vierteljährliche Audits räumen alte Tasks und Doppelstarts auf – erstaunlich oft laufen verwaiste Skripte weiter. Bei anhaltender Knappheit ziehe ich auf einen VPS um und entlaste das System durch dedizierte Kerne. Das kostet vielleicht ein paar Euro, spart aber deutlich mehr durch stabile Reaktionszeiten.
Ich dokumentiere jeden Cronjob: Zweck, Intervall, durchschnittliche Dauer, Notfallkontakt. Änderungen teste ich in Stufen, beobachte Metriken und rolle bei Bedarf zurück. Für Teams hilft ein Runbook mit klaren Schritten bei Verzögerungen oder Ausfällen. Wer Cron-Änderungen wie Code behandelt, vermeidet Nebeneffekte. Mit sauberen Prozessen bleiben Intervalle langfristig passend.
Kurz zusammengefasst
Ich wähle Cronjob-Intervalle nicht nach Gefühl, sondern nach Laufzeit, I/O-Profil und Nutzerwirkung. Eng getaktete, schwere Tasks führen zu Überlappungen und frühen Peaks, weit gesetzte, gut verteilte Intervalle glätten die Kurve. Skript-Tuning, Locking und Prioritäten wirken oft stärker als ein bloßes Strecken des Takts. Queues, externer Cron und echte Server-Crons entkoppeln Arbeit vom Besucherverhalten. Mit Monitoring, SLOs und regelmäßigen Audits halte ich die Serverlast dauerhaft im grünen Bereich.


