Die WP-CLI macht es relativ einfach, bestimmte Aufgaben direkt über die Linux-Konsole zu starten. Das hat mehrere Vorteile. Unter anderem diese, die ich selbst sehr schätze:
- Aufgaben sind unter Umständen schneller erledigt. Das Einloggen und rumspielen im Backend entfällt.
- PHP
max_execution_time
steht automatisch auf 0 und die Scripte können länger laufen als gewöhnlich. - Der Weg zu PHP über einen Webserver entfällt.
Lange laufende Scripte: ein Problem auf fast jedem Webspace
Programmiert man einen Cronjob von den man von Anfang an weiß, dass er sehr lange laufen wird, ist das ursprüngliche Cron-Management von WordPress ein Problem. Genauer gesagt eigentlich die Serverkonfiguration die fast überall so eingestellt ist, dass ein Script nach einer gewissen Zeit abbricht. Und das ist ja letztlich auch gut so. So stellt man sicher, dass unkontrollierte Skripte nicht unendlich lange laufen können.
Bei einem Kunden stand ich genau vor dieser Aufgabe: Lang laufende Cronjobs weil Daten von einem Drittanbieter abgerufen werden müssen dessen Webserver manchmal nicht so schnell antworten, wie man das vielleicht hoffen würde.
Die Frage ist also:
Wie geht man der Situation um, wenn ein Skript plötzlich abbricht?
Die Lösung ist das Zwischenspeichern der aktuellen Stati. In meinem Beispiel lade ich zuerst eine Liste von URLs die abgerufen werden müssen. Ich kann also diese URLs zwischenspeichern und mitloggen, welche davon bereits erledigt wurden. Wenn das Script abbricht und es neu gestartet wird, weiß es, wo es weitermachen muss.
Man würde jetzt meinen, dass die folgende PHP-Funktion dafür ausreichend sein würde: register_shutdown_function()
. Man registriert eine PHP-Funktion die aufgerufen wird, bevor PHP die Ausführung beendet.
Das Problem dabei ist: Die Funktion, die über register_shutdown_function() registriert wurde, wird nicht aufgerufen, wenn PHP über die CLI aufgerufen wird (d.h. auch nicht über die WP-CLI).
register_shutdown_function bei CLI-Anwendungen
Die Lösung ist die Funktion pcntl_signal
. Sie funktioniert letztlich ähnlich wie register_shutdown_function()
aber funktioniert auch auf CLI-Ebene. Am besten man definiert zwei Alternativen:
if ( function_exists( 'pcntl_signal' ) ) {
pcntl_signal( SIGINT, 'xct_cron_sigint' );
pcntl_signal( SIGTERM, 'xct_cron_sigint' );
}
- SIGINT steht für “Signal Interrupt”. Es entsteht, wenn ein User das Script abbricht. Das kann z.B. über den Befehl Strg+C auf der Tastatur geschehen.
- SIGTERM ist eine Beendigungsanfrage. Sie entsteht in der Regel, wenn das Script fertig durchgelaufen ist oder es durch einen anderen Prozess beendet wird (z.B. über die “kill” Anweisung).
Das doofe ist nur: pcntl_singal
ist nicht auf jedem Webserver verfügbar 🙁