Ich habe ein Cron-Skript, das alle 10 Minuten ein PHP-Skript ausführt. Das Skript überprüft eine Warteschlange und verarbeitet die Daten in der Warteschlange. Manchmal verfügt die Warteschlange über genügend Daten, um über 10 Minuten der Verarbeitung zu dauern, wodurch das Potenzial von zwei Skripts entsteht, die versuchen, auf dieselben Daten zuzugreifen. Ich möchte feststellen können, ob das Skript bereits ausgeführt wird, um zu verhindern, dass mehrere Kopien des Skripts gestartet werden. Ich dachte darüber nach, ein Datenbank-Flag zu erstellen, das besagt, dass ein Skript verarbeitet wird, aber wenn das Skript jemals abstürzen würde, würde es im positiven Zustand bleiben. Gibt es eine einfache Möglichkeit festzustellen, ob das PHP-Skript bereits mit einem PHP- oder Shell-Skript ausgeführt wird?
Wenn Sie es absolut crashsicher benötigen, sollten Sie Semaphore verwenden, die veröffentlicht werden automatisch, wenn php die spezifische Bearbeitung der Anfrage beendet.
Ein einfacherer Ansatz wäre, einen DB-Datensatz oder eine Datei zu Beginn der Ausführung zu erstellen und am Ende zu entfernen. Sie können immer das "Alter" dieses Datensatzes / Datei überprüfen, und wenn es älter ist als sagen 3 Mal die normale Skriptausführung, angenommen, dass es abgestürzt ist und es entfernen.
Es gibt keine "Wunderwaffe", es hängt nur von Ihren Bedürfnissen ab.
Sie können einfach eine Sperrdatei verwenden. PHPs flock()
Funktion bietet einen einfachen Wrapper für Unix's flock
Funktion, die beratende Sperren für Dateien bietet.
Wenn Sie sie nicht explizit freigeben, wird das Betriebssystem diese Sperren automatisch für Sie freigeben, wenn der Prozess, der sie enthält, beendet wird, selbst wenn es abnormal beendet wird.
Sie können auch der lockeren Unix-Konvention folgen, Ihre Lock-Datei zu einer 'PID-Datei' zu machen - das heißt, nachdem Sie eine Sperre für die Datei erhalten haben, lassen Sie Ihr Skript seine PID schreiben. Auch wenn Sie dies nie in Ihrem Skript lesen, ist es für Sie praktisch, wenn Ihr Skript jemals hängt oder verrückt wird und Sie seine PID finden möchten, um es manuell zu beenden.
Hier ist eine Copy / Paste-Ready-Implementierung:
%Vor%Legen Sie einfach den Pfad Ihrer Sperrdatei fest, wo Sie möchten, und Sie sind eingestellt.
Wenn Sie Linux ausführen, sollte dies am Anfang Ihres Skripts funktionieren:
%Vor%Eine übliche Methode für * nix-Daemons (obwohl nicht unbedingt PHP-Skripte, aber es wird funktionieren) ist die Verwendung einer .pid-Datei.
Wenn das Skript startet, prüfen Sie, ob eine .pid-Datei existiert, die nach dem Skript benannt ist (normalerweise in / var / run / gespeichert). Wenn es nicht existiert, erstellen Sie es, indem Sie seinen Inhalt auf die PID des Prozesses setzen, der das Skript ausführt (mit getmypid ) und dann mit der normalen Ausführung fortfahren. Wenn es existiert, lesen Sie die PID aus und sehen Sie, ob dieser Prozess noch läuft, wahrscheinlich indem Sie ps $pid
ausführen. Wenn es ausgeführt wird, beenden Sie es. Andernfalls überschreiben Sie den Inhalt mit Ihrer PID (wie oben) und fahren mit der normalen Ausführung fort.
Wenn die Ausführung beendet ist, löschen Sie die Datei.
Ich weiß, dass das eine alte Frage ist, aber für den Fall, dass jemand anderes hier schaut, poste ich etwas Code. Dies habe ich kürzlich in einer ähnlichen Situation gemacht und es funktioniert gut. Setzen Sie diesen Code an den Anfang Ihrer Datei und wenn das gleiche Skript bereits läuft, wird es belassen und das neue beenden.
Ich benutze es, um ein Überwachungssystem jederzeit laufen zu lassen. Ein Cron-Job startet das Skript alle 5 Minuten, aber wenn der andere nicht aus irgendeinem Grund gestoppt wurde (normalerweise, wenn es abgestürzt ist, was sehr selten ist!), Beendet sich der neue einfach selbst.
%Vor%Es wird NICHT ohne Änderung unter Windows funktionieren, aber sollte in Unix-basierten Systemen in Ordnung sein.
Das hat für mich funktioniert. Legen Sie einen Datenbankdatensatz mit einem Sperrkennzeichen und einem Zeitstempel fest. Mein Skript sollte gut innerhalb von 15 Minuten abgeschlossen sein, also als letztes gesperrtes Feld hinzugefügt werden, um zu überprüfen:
%Vor%Entsperren Sie es am Ende des Skripts:
%Vor%Ich habe das versucht. Funktioniert auch in Windows gut.
%Vor%Danke an @martinodf für seine Idee.
Ich weiß, dass dies eine alte Frage ist, aber es gibt einen Ansatz, der bisher noch nicht erwähnt wurde, und ich denke, dass es eine Überlegung wert ist.
Eines der Probleme mit einer Sperrdatei- oder Datenbank-Flag-Lösung besteht darin, dass, wenn das Skript aus einem anderen Grund als der normalen Beendigung fehlschlägt, die Sperre nicht aufgehoben wird. Daher wird die nächste Instanz erst starten, wenn die Sperre entweder manuell gelöscht oder durch eine Bereinigungsfunktion gelöscht wurde.
Wenn Sie jedoch sicher sind, dass das Skript nur einmal ausgeführt werden soll, ist es relativ einfach, innerhalb des Skripts zu überprüfen, ob es beim Starten bereits ausgeführt wird. Hier ist ein Code:
%Vor%Rufen Sie diese Funktion einfach am Anfang des Skripts auf, bevor Sie etwas anderes tun (z. B. einen Datenbankhandler öffnen oder eine Importdatei verarbeiten). Wenn das gleiche Skript bereits ausgeführt wird, wird es zweimal in der Prozessliste angezeigt - einmal für die vorherige Instanz und einmal für diese. Also, wenn es mehr als einmal erscheint, einfach verlassen.
Hier ist ein potenzielles Problem: Ich gehe davon aus, dass Sie nie zwei Skripte mit demselben Basisnamen haben werden, die legitimerweise gleichzeitig laufen können (zB das gleiche Skript läuft unter zwei verschiedenen Benutzern). Wenn das eine Möglichkeit ist, müssen Sie die Überprüfung auf etwas komplizierteres als eine einfache Teilzeichenfolge für den Basisnamen der Datei erweitern. Aber das funktioniert gut genug, wenn Sie eindeutige Dateinamen für Ihre Skripte haben.
Fügen Sie einfach oben auf Ihrem Skript Folgendes hinzu:
%Vor%