1. 程式人生 > >使用fastcgi_finish_request 處理耗時的任務

使用fastcgi_finish_request 處理耗時的任務

我們業務中經常遇到這樣的場景:比如生成檔案較大的excel ,非常耗時,有可能需要5到30妙的時間,甚至更長導致瀏覽器連線超時。
另外一個就是體驗問題,使用者需要長時間的等待響應的完畢,體驗較差。
類似的場景還有
1:需要處理大的檔案
2:傳送郵件或簡訊,尤其是需要迴圈傳送郵件通知等
3:呼叫遠端耗時的api 等

遇到這種情況,如果您的伺服器使用的也是nginx ,那麼可以考慮使用下面的函式

fastcgi_finish_request();

該函式的作用:
理解發送響應給瀏覽器,這樣使用者的等待時間很短,但是php程序其實還在伺服器中執行。
這樣就達到了兩個目錄目的,有點類似於非同步任務

  1. 響應快:比如傳送郵件需要3秒時間,但使用者無感知,1妙之內就告訴使用者傳送郵件完畢
  2. 耗時任務後臺執行:瀏覽器響應結束了,使用者可以做其他的事情。後臺程序默默的執行傳送郵件等任務

舉例效果圖:
1:該程式模擬一個耗時的任務,需要5妙才能執行完畢
在這裡插入圖片描述
經過上面的演示,我們達到了目的
1:很快的響應,1毫米之內,瀏覽器響應結束
2:後臺任務,注意右側上方的日誌,每秒輸出一個時間戳

全部測試程式碼如下

 <?php
/**
 * 設定超時時間,變成不限制
 *
 */
set_time_limit(0);

/**
 * 本函式模擬非常耗時的任務,執行完畢需要5秒的時間
 */
 function writeFile()
 {
     $path = '/home/ndw/test/1.txt';
     file_put_contents($path,'程式執行開始' . PHP_EOL,FILE_APPEND);
     for($i =0;$i < 5;$i++) {
         file_put_contents($path,time() . PHP_EOL,FILE_APPEND);
         sleep(1);
     }

     file_put_contents($path,'程式執行結束' . PHP_EOL,FILE_APPEND);

 }

/**
 * 輸出文字標記,任務開始
 */
echo('任務開始');

/**
 *  後臺執行非常耗時的任務
 */
register_shutdown_function(writeFile);

/**
 * 立即傳送請求
 */
fastcgi_finish_request();


備註:

  • 主角是fastcgi_finish_request,其實把要執行的程式碼放到該函式的後面,就可以了。
  • register_shutdown_function函式,具體百度,這個函式主要是為了考慮修改成本,有的程式已經成型,不方便作大的調整,可以把函式提前註冊,這樣他是不會立即執行的。頁面響應完畢後,再呼叫本函式
  • 建議不要濫用,適合一些耗時但流程簡單的任務(比如傳送郵件)。因為是後臺執行,如果程式出錯,前臺是看不到的,需要有日誌記錄和重試機制。