Heim >Backend-Entwicklung >PHP-Problem >Was soll ich tun, wenn die Flock-PHP-Sperre fehlschlägt?

Was soll ich tun, wenn die Flock-PHP-Sperre fehlschlägt?

藏色散人
藏色散人Original
2021-11-08 09:32:402294Durchsuche

flock PHP-Sperrfehler wird dadurch verursacht, dass $file_lock nach dem Beenden der isRunning()-Methode nicht verwendet wird. Die Lösung besteht darin, sicherzustellen, dass das Dateihandle während des gesamten PHP-Lebenszyklus nicht freigegeben wird.

Was soll ich tun, wenn die Flock-PHP-Sperre fehlschlägt?

Die Betriebsumgebung dieses Artikels: Windows 7-System, PHP-Version 7.1, DELL G3-Computer

Was soll ich tun, wenn die PHP-Sperre fehlschlägt?

Lösung für das PHP-Flock-Fehlerproblem:

In den letzten zwei Tagen habe ich eine Methode für mein Nebenprojekt geschrieben, um die gleichzeitige Ausführung von PHP-Skripten zu vermeiden, die von crontab geplant werden.

So geht's

Im Allgemeinen sperrt dasselbe PHP-Skript dieselbe Festplattendatei nicht blockierend, wenn die Datei belegt ist, sodass das Skript dies tun kann sofort verlassen.

Phänomen

Aber in der Praxis hat sich herausgestellt, dass es möglich ist, direkt in der Controller-Datei zu flocken, aber wenn die Flock-Logik in eine Funktion in anderen Dateien gekapselt wird, wird sie ungültig.

Ursache

Nachdem ich lange debuggt hatte, fiel mir plötzlich ein, dass ich schon einmal auf diese Falle gestoßen war. .

Der Fehlercode lautet wie folgt:

class Crontab
{
    /**
     * 确保任务没有并发执行
     */
    public static function isRunning() {
        global $argv;
        $ident = [];
        foreach ($argv as $idx => $value) {
            $ident[] = $idx . '=' . urlencode($value);
        }
        $ident = md5(implode('&', $ident));
        $lockDir = \Yii::getAlias('@app/runtime/crontab/');
        @mkdir($lockDir, 0755, true);
        $file_lock = fopen($lockDir . $ident, 'w+');
        $wouldBlock = 0;
        flock($file_lock, LOCK_EX | LOCK_NB, $wouldBlock);
        return $wouldBlock;
    }
}
class Crontab
{
    /**
     * 确保任务没有并发执行
     */
    public static function isRunning() {
        global $argv;
 
        $ident = [];
        foreach ($argv as $idx => $value) {
            $ident[] = $idx . '=' . urlencode($value);
        }
        $ident = md5(implode('&', $ident));
 
        $lockDir = \Yii::getAlias('@app/runtime/crontab/');
 
        @mkdir($lockDir, 0755, true);
 
        $file_lock = fopen($lockDir . $ident, 'w+');
 
        $wouldBlock = 0;
        flock($file_lock, LOCK_EX | LOCK_NB, $wouldBlock);
 
        return $wouldBlock;
    }
}

Generieren Sie einen eindeutigen Hash-Wert basierend auf den Befehlszeilenparametern, der die PHP-Aufgabe darstellt.

Erstellen Sie eine Sperrdatei, führen Sie die nicht blockierende Flock-Sperre aus und geben Sie wouldBlock zurück, um festzustellen, ob die Sperre belegt ist.

Ich habe die Methode Crontab::isRunning() am Skripteintrag aufgerufen und festgestellt, dass nach gleichzeitigem Starten des Skripts die Sperre immer erhalten werden kann.

Der Grund für den Fehler ist: Nach dem Beenden der isRunning()-Methode wird $file_lock nicht mehr verwendet und ist ein von PHP gesammelter Müll. Das $fp-Dateihandle wird geschlossen, wodurch die Sperre automatisch aufgehoben wird.

Lösung

class Crontab
{
    /**
     * 保存起来避免被php作为垃圾回收
     * @var null
     */
    static $file_lock = null;
    /**
     * 确保任务没有并发执行
     */
    public static function isRunning() {
        global $argv;
        $ident = [];
        foreach ($argv as $idx => $value) {
            $ident[] = $idx . '=' . urlencode($value);
        }
        $ident = md5(implode('&', $ident));
        $lockDir = \Yii::getAlias('@app/runtime/crontab/');
        @mkdir($lockDir, 0755, true);
        self::$file_lock = fopen($lockDir . $ident, 'w+');
        $wouldBlock = 0;
        flock(self::$file_lock, LOCK_EX | LOCK_NB, $wouldBlock);
        return $wouldBlock;
    }
}
class Crontab
{
    /**
     * 保存起来避免被php作为垃圾回收
     * @var null
     */
    static $file_lock = null;
 
    /**
     * 确保任务没有并发执行
     */
    public static function isRunning() {
        global $argv;
 
        $ident = [];
        foreach ($argv as $idx => $value) {
            $ident[] = $idx . '=' . urlencode($value);
        }
        $ident = md5(implode('&', $ident));
 
        $lockDir = \Yii::getAlias('@app/runtime/crontab/');
 
        @mkdir($lockDir, 0755, true);
 
        self::$file_lock = fopen($lockDir . $ident, 'w+');
 
        $wouldBlock = 0;
        flock(self::$file_lock, LOCK_EX | LOCK_NB, $wouldBlock);
 
        return $wouldBlock;
    }
}

Stellen Sie einfach sicher, dass das Dateihandle während des gesamten PHP-Lebenszyklus nicht freigegeben wird, sodass es in der statischen Mitgliedsvariablen der Klasse gespeichert wird.

Empfohlenes Lernen: „PHP-Video-Tutorial

Das obige ist der detaillierte Inhalt vonWas soll ich tun, wenn die Flock-PHP-Sperre fehlschlägt?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn