Die klassische Konfigurationsdatei für Cron-Job-Einträge im Linux-Betriebssystem lautet wie folgt:
Die ersten fünf Parameter geben die Ausführungszeit dieser Aufgabe an, und der sechste - der Befehl selbst, der ausgeführt werden muss. Zeitparameter sind: Minuten, Stunden, Tage, Monate und Wochentag. Darüber hinaus müssen alle Zahlen als Ganzzahlen oder in Form einer speziellen Syntax dargestellt werden .Infolgedessen beträgt das minimal mögliche Intervall zum Starten eines Befehls einmal pro Minute.Für viele Aufgaben wird die Befehlsausführung viel häufiger benötigt, beispielsweise alle 10 Sekunden. Bei einigen Aufgaben zur Automatisierung von Geschäftsprozessen beträgt die maximal zulässige Verzögerung häufig nicht mehr als 1 bis 1,5 Sekunden.Natürlich ist der klassische Cron dafür nicht geeignet - er muss verbessert werden.Im Folgenden finden Sie eine schrittweise Implementierung zum Erstellen zusätzlicher Funktionen (in PHP) für das klassische Cron unter Linux unter Verwendung eines zusätzlichen Schutzes gegen Neustartprozesse.Aufgabeneinstellung und Cron-Einrichtung
Zum Beispiel werden wir die folgende Aufgabe verwenden:- Im Frontend kann der Benutzer die Ausführung einer komplexen Aufgabe durch Klicken auf die Schaltfläche "Ausführen" einleiten.
- Das Backend nach dem Schreiben einer neuen Zeile in die Datenbank informiert den Benutzer über die Bestätigung.
- Über cron werden wir solche neuen Aufgaben „verfolgen“ und so schnell wie möglich erledigen, damit der Benutzer das Ergebnis nicht in einer Minute, sondern sofort * erhält.
* Wenn Sie den Start von Befehlen nur pro Minute verwenden, wird die Aufgabe gestartet, wenn die Sekunden die nächste Null erreichen (den Beginn einer neuen Minute). Daher muss der Benutzer in der klassischen Form von 0 bis 59 Sekunden auf die Ausführung warten.So wird cron in seiner maximalen Form konfiguriert, d.h. einmal pro Minute:* * * * * /usr/bin/php -q /run.php > /dev/null 2>&1
Einzelzyklus
Zunächst sollten Sie entscheiden, wie oft neue Aufgaben in der Datenbank angefordert werden sollen. Abhängig davon ändern sich die Anzahl der Zyklen und der logische Ruhezustand (Funktion sleep
) .Im aktuellen Beispiel wird ein Schritt von 10 Sekunden verwendet. Daher beträgt die Anzahl der Zyklen 60/10 = 6. Insgesamt lautet der allgemeine Code wie folgt:for ($cycle = 1; $cycle <= 6; $cycle++) {
$all_tasks = get_all_tasks();
if ($all_tasks) {
foreach($all_tasks as $one_task) {
solve_one_task($one_task);
}
}
sleep(10);
}
Erläuterung : In diesem Beispiel wird ein Schritt von 10 Sekunden verwendet, der alle 10 Sekunden ein Mindestintervall für die Skriptausführung bereitstellen kann. Dementsprechend sollten Sie für eine häufigere Ausführung die Anzahl der Zyklen und die "Schlafzeit" ändern.Vermeiden der wiederholten Ausführung von Aufgaben
In der dargestellten Form gibt es eine Unsicherheit, nämlich die wiederholte Ausführung der Aufgabe, wenn sie bereits gestartet wurde. Dies gilt insbesondere dann, wenn die Aufgabe "schwierig" ist und einige Sekunden benötigt, um sie zu implementieren.Dies führt zu einem erneuten Ausführungsproblem:- Die Funktion wird
solve_one_task()
bereits ausgefĂĽhrt, hat ihre Arbeit jedoch noch nicht abgeschlossen. - Daher wird die Aufgabe in der Datenbank immer noch als nicht erfĂĽllt markiert.
- Im nächsten Zyklus wird diese Aufgabe erneut ausgeführt und die Funktion
solve_one_task()
mit derselben Aufgabe erneut ausgefĂĽhrt.
Dies kann natürlich gelöst werden, indem beispielsweise ein Status in der Datenbank für diese Aufgabe geändert wird.Wir werden die Datenbank jedoch nicht laden: Aufgrund meiner Tests kann MYSQL die Anforderung akzeptieren, aber nicht sofort verarbeiten. Eine Differenz von sogar 0,5 Sekunden kann zu einer wiederholten Ausführung führen - was kategorisch nicht geeignet ist.Auch in diesem Fall sprechen wir nur über den Status von Aufgaben, daher ist es besser, das Dateisystem des Servers zu verwenden.Das grundlegende Überprüfungsmodell wird mit flock
einer Funktion erstellt, mit der eine Datei festgelegt und entsperrt wird.In der PHP-AusfĂĽhrung kann die Funktion wie folgt dargestellt werden:$lock_file_abs = 'file';
$fp = fopen($lock_file_abs,"w+");
if (flock($fp, LOCK_EX | LOCK_NB)) {
solve_one_task($one_task);
flock($fp, LOCK_UN);
}
else {
}
fclose($fp);
unlink($lock_file_abs);
Ergebnis
Die allgemeine Ansicht des gesamten Zyklus ist wie folgt:for ($cycle = 1; $cycle <= 6; $cycle++) {
$all_tasks = get_all_tasks();
if ($all_tasks) {
foreach($all_tasks as $one_task) {
$lock_file_abs = __DIR__.'/locks/run_'.$one_task['id'];
$fp = fopen($lock_file_abs,"w+");
if (flock($fp, LOCK_EX | LOCK_NB)) {
solve_one_task($one_task);
flock($fp, LOCK_UN);
}
else {
}
fclose($fp);
unlink($lock_file_abs);
}
}
sleep(10);
}
Ein solcher Algorithmus ermöglicht es Ihnen daher, eine zyklische Ausführung der Aufgabenverarbeitung zu starten, und befürchtet nicht, dass die Aufgabe mehr als einmal verarbeitet wird.Und jetzt reicht es aus, diesen Code einfach jede Minute durch cron zu führen, und es werden wiederum kleinere Zyklen ausgeführt, die bereits in sich selbst enthalten sind.