2017-05-03 2 views
0

Ich muss ein PHP Skript ausführen, ich möchte sicherstellen, dass nicht mehr als ein Skript zur gleichen Zeit ausgeführt wird.Wie man Einzel-Thread-Job mit MySQL-Datenbank verwalten?

ich mysql verwende, und ich dachte über diese Lösung:

Ich baue die unten Datenbank:

 job_id    | task_id | last_updated_time (AUTO UPDATE) 
    "sending_emails"    77238  2107-5-3 12:2:2 

Bevor Sie das Skript ausführen ich zufällige Aufgabe ID erstellen, dann betreibe ich eine Abfrage zu aktualisieren die Aufgaben-ID

$task_id = generate_random_task_id(); 
    $query = " 
        UPDATE 
         jobs 
        SET 
         task_id = $task_id 
        WHERE 
         task_id = $task_id 
         OR 
         NOW() - last_updated_time > 30 
        LIMIT 1 
      " 

/* 
    Then I need to check if there was an update, if yes then I will run the script otherwise i will stop since there is already another script running 
*/ 

$query = "SELECT JOB_ID WHERE taks_id = $task_id " 
$result = run($query) 
if(! isset($result[JOB_ID])){ 
    DIE(); 
} 

Gibt es eine Chance, dass zwei Skripte gleichzeitig laufen?

Antwort

0

Nein, sie können nicht gleichzeitig ausgeführt werden, here's MySQL-Dokumentation über UPDATE und SELECT, ist es das, was es sagt:

UPDATE ... WHERE ... eine exklusive Next-Key-Sets Sperre auf jeden Datensatz die Suche trifft. Für Anweisungen, die Zeilen unter Verwendung eines eindeutigen Indexes für die Suche nach einer eindeutigen Zeile sperren, ist jedoch nur eine Indexdatensatzsperre erforderlich .

Here's mehr über geteilt und Schreibsperren:

A Shared (S) Verriegelung erlaubt die Transaktion, die die Sperre eine Zeile zu lesen, enthält.

Eine exklusive (X) Sperre ermöglicht die Transaktion, die die Sperre auf enthält, aktualisieren oder löschen eine Zeile.

Wenn eine Transaktion T1 eine Exklusivsperre (X) für Zeile r enthält, kann eine Anforderung aus einer bestimmten Transaktion T2 für eine Sperre eines der beiden Typen unter r nicht sofort erteilt werden. Stattdessen muss Transaktion T2 auf Transaktion T1 warten, um seine Sperre für Zeile r freizugeben.

0

Ja, es gibt jede Chance, dass Sie die gleiche Aufgabe erneut ausführen können.

Es gibt zwei offensichtliche Lösungen.

Eine ist es, eine mysql-Verbindung zu öffnen und dann eine Sperre unter Verwendung GET_LOCK() mit einem kurzen Timeout zu erwerben - wenn Sie die Sperre dann erhalten, sind Sie gut zu gehen. Sie müssen die Datenbankverbindung für die Lebensdauer des Skripts beibehalten.

Alternativ können Sie eine Tabelle mit einer eindeutigen Einschränkung für finish_time erstellen, einen Datensatz mit einer Null-Beendigungszeit einfügen, um den Start anzuzeigen (es wird fehlschlagen, wenn bereits ein Datensatz mit einer Null-Beendigungszeit vorhanden ist), dann die Zielzeit auf aktualisieren NOW(), wenn es abgeschlossen ist.

Die Verwendung der Datenbank zur Darstellung des Status einer laufenden Task ist jedoch nur sinnvoll, wenn die Task innerhalb eines losly-gekoppelten, aber hoch verfügbaren Clusters ausgeführt wird - was bedeutet, dass die Datenbank ebenfalls gruppiert ist. Und die Art des Clusterns (NDB, Asych, Semi-Sync, Multi-Master) hat großen Einfluss darauf, wie sich das in der Praxis verhalten wird.

OTOH Wenn dies nicht der Fall ist, ist die Verwendung der Datenbank zur Darstellung des Status der falsche Weg, um das Problem zu lösen.

+0

Vielen Dank für Ihre Antwort, aber ich bin mir nicht sicher, warum finish_time funktioniert, und meins wird nicht funktionieren? –

+0

Könnten Sie bitte @ Darshan Mehta Antwort sehen! –

+0

Abgesehen von den Komplikationen, die sich bei der Ausführung von Berechnungen in SQL ohne Angabe des Intervalls ergeben, wird Ihr Ziel nur erreicht, wenn Sie * garantieren *, dass die Ausführung weniger als 30 Sekunden dauert. Abhängig von Ihrem Nebenläufigkeitsmodell in der Datenbank ergeben sich auch Race Conditions. Außerdem haben Sie in Ihrem Beispiel eine sehr niedrige Entropie bei der Generierung Ihrer Task-IDs - und wenn Sie diese mit hoher Häufigkeit ausführen, werden Sie irgendwann mit einer Kollision enden. Muss ich weitermachen? – symcbean

0

Ja, sie können gleichzeitig laufen. Wenn Sie wollen, einer nach dem anderen laufen SELECT Abfrage geändert werden sollte:

SELECT JOB_ID WHERE taks_id = $task_id LOCK IN SHARED MODE 

In diesem Fall verwendet es eine Lesesperre.

Dies ist das gleiche, ob Sie NDB oder InnoDB verwenden.

Verwandte Themen