php程式daemon化的正確做法

elarity發表於2019-02-16

[原文地址:https://blog.ti-node.com/blog…]

daemon 音標 : [`di:mən] , 中文含義為守護神或精靈的意思 . 其實它還有個意思 : 守護程式 .

守護程式簡單地說就是可以脫離終端而在後臺執行的程式 . 這在Linux中是非常常見的一種程式 , 比如apache或者mysql等服務啟動後 , 就會以守護程式的方式進駐在記憶體中 .

以PHP為例 , 假如我有個耗時間的任務需要跑在後臺 : 將所有mysql中user表中的2000萬使用者全部匯入到redis中做預熱快取 , 那麼這個任務估計一時半會是不會結束的 , 這個時候就需要編寫一個php指令碼以daemon形式執行在系統中 , 結束後自動推出 .

在Linux中 , 大概有三種方式實現指令碼後臺化 :

1 . 在命令後新增一個&符號 , 比如 php task.php & . 這個方法的缺點在於 如果terminal終端關閉 , 無論是正常關閉還是非正常關閉 , 這個php程式都會隨著終端關閉而關閉 , 其次是程式碼中如果有echo或者print_r之類的輸出文字 , 會被輸出到當前的終端視窗中 .

2 . 使用nohup命令 , 比如 nohup php task.php & . 預設情況下 , 程式碼中echo或者print_r之類輸出的文字會被輸出到php程式碼同級目錄的nohup.out檔案中 . 如果你用exit命令或者關閉按鈕等正常手段關閉終端 , 該程式不會被關閉 , 依然會在後臺持續執行 . 但是如果終端遇到異常退出或者終止 , 該php程式也會隨即退出 . 本質上 , 也並非穩定可靠的daemon方案 .

3 . 使用fork和setsid , 我暫且稱之為 : *nix解決方案 . 具體看下程式碼 :

<?php
    // 一次fork  
    $pid = pcntl_fork();
    if ( $pid < 0 ) {
      exit( ` fork error. ` );
    } else if( $pid > 0 ) {
      exit( ` parent process. ` );
    }
    // 將當前子程式提升會會話組組長 這是至關重要的一步 
    if ( ! posix_setsid() ) {
      exit( ` setsid error. ` );
    }
    // 二次fork
    $pid = pcntl_fork();
    if( $pid < 0 ){
      exit( ` fork error. ` );
    } else if( $pid > 0 ) {
      exit( ` parent process. ` );
    }
    
    // 真正的邏輯程式碼們 下面僅僅寫個迴圈以示例
    for( $i = 1 ; $i <= 100 ; $i++ ){
      sleep( 1 );
      file_put_contents( `daemon.log`, $i, FILE_APPEND );
    }
?>

相關文章