2013-12-11 26 views
2

我有一個從cron運行每分鐘的php腳本。但有時它的工作時間超過1分鐘。 我的問題是:確保現在只有一個進程正在運行的最佳方式是什麼?確保在Linux上只有一個正在運行的PHP進程

我用這個代碼:

$output = shell_exec('ps aux | grep some_script.php | grep -v grep'); //get all processes containing "some_script.php" and exclude current grep process 
$trimmed = rtrim($output, PHP_EOL); //trim newline symbol in the end 
$processes = explode(PHP_EOL, $trimmed); //get the array of lines (i.e. processes) 
$procCnt = count($processes); //get number of lines 
if ($procCnt > 2) { 
    echo "busy\n"; 
    exit();  //exit if number of processes more than 2 (see explaination below) 
} 

如果有cron中運行一個some_script過程,了shell_exec返回類似的東西:在輸出

apache  13593 0.0 0.0 9228 1068 ?  Ss 18:20 0:00 /bin/bash -c php -f /srv/www/robot/some_script.php 2>&1 
apache  13602 0.0 0.0 290640 10544 ?  S 18:20 0:00 php -f /srv/www/robot/some_script.php 

所以超過2,如果我有線條,我致電退出()

我想問:我是否正確?或者,還有更好的方法?

任何幫助,將不勝感激

回答

3

檢查這種方式創建競爭條件,其中兩個進程可以同時檢索列表,然後雙方決定退出。取決於你想要做什麼,這可能會也可能不會成爲問題。

可能更好的選擇是創建某種鎖。我用過的一個簡單的目錄是隻在進程運行時存在的目錄 - mkdir是原子的,它會成功(沒有其他進程正在運行)或失敗(另一個進程已經創建它)。只要確保在完成時將其刪除:

if (!mkdir("lock_dir")) { 
    echo "busy\n"; 
    exit(); 
} 
register_shutdown_function(function() { 
    rmdir("lock_dir"); 
}); 

或更好,它看起來像flock是爲了類似的目的。這是手冊中的示例:

<?php 

$fp = fopen("/tmp/lock.txt", "r+"); 

if (flock($fp, LOCK_EX)) { // acquire an exclusive lock 
    ftruncate($fp, 0);  // truncate file 
    fwrite($fp, "Write something here\n"); 
    fflush($fp);   // flush output before releasing the lock 
    flock($fp, LOCK_UN); // release the lock 
} else { 
    echo "Couldn't get the lock!"; 
} 

fclose($fp); 

?> 

只需按住腳本運行時的鎖定,就像我的第一個示例一樣。

+0

我應該添加,就我所知__ PHP的mkdir是原子。如果我錯了,那麼使用關機功能的羊羣可能會更好。 – Izkata

+0

我不知道register_shutdown_function。非常感謝你!它訣竅 – Curious

+1

register_shutdown_function可能無法調用某些類型的錯誤。要真正實現它,我會爲鎖添加「過期」。檢查文件夾的filemtime,如果超過15分鐘,刪除它並繼續使用cron(你也可以用腳本殺死所有php進程)。 –

1

最簡單的方法是創建過程,同時啓動文件,並在極底刪除。 並檢查文件是否存在,然後繼續並創建它或死。

另一個是限制MaxClients爲apache(如果它是有效的選項在你的情況)。

+0

感謝快速回復!我想過這個方法,但是如果腳本中有一個致命的錯誤(沒有人是完美的),它會被終止,並且文件不會被刪除 – Curious

+0

@Izkata的答案有一個解決方案 - register_shutdown_function – Curious

+0

@ ZUB如果文件存在檢查其創建時間(使用統計功能) - 比幾分鐘早,比刪除和照常進行, – StormRideR

0

只用於OOP風格,我使用分離的助手類。

flock — Portable advisory file locking

register_shutdown_function — Register a function for execution on shutdown

<?php 

class ProcessHelper 
{ 
    const PIDFILE = 'yourProcessName.pid'; 

    public static function isLocked() 
    { 
     $fp = fopen(self::PIDFILE, 'w'); 

     if (!flock($fp, LOCK_EX | LOCK_NB, $wouldBlock)) { 
      if ($wouldBlock) { 
       // if this file locked by other process 
       var_dump('DO NOTHING'); 
       return true; 
      } 
     } else { 
      var_dump('Do something and remove PID file'); 
      register_shutdown_function(function() { 
       unlink(self::PIDFILE); 
      }); 
      sleep(5); //for test, uncomment 
     } 
     return false; 
    } 
} 


class FooService 
{ 
    public function init() 
    { 
     if (!ProcessHelper::isLocked()) { 
      var_dump('count 1000\n'); 
      for ($i = 0; $i < 10000; $i++) { 
       echo $i; 
      } 
     } 
    } 
} 

$foo = new FooService(); 
$foo->init(); 
相關問題