1. 程式人生 > 其它 >PHP 實現請求結束之後,後臺靜默執行部分程式碼

PHP 實現請求結束之後,後臺靜默執行部分程式碼

技術標籤:php後端php後端

這一篇其實是由上一篇引申出來的。之前說到,勉勉強強實現了 PDF 和 PPT 檔案轉圖片,但是轉換需要一定的時間,而我這裡是使用者發起請求進行轉換的,這部分時間不應該讓使用者一直等著,應該結束請求,把資料返回給使用者,然後後臺再慢慢執行這些轉換操作。

最開始我是有兩種想法的,第一種是比較傳統的,做一個進度條給使用者看,雖然一個檔案稍微要幾秒鐘的等待時間,但是有了進度條之後也勉強能夠接受;第二種就是我現在在實現的辦法,即結束請求,把資料返回給前端,然後後臺再默默地進行轉換操作。這裡我綜合考慮了一下,選擇了第二種實現方法。

有了想法的雛形之後,就開始瘋狂搜索尋找可行的解決方法了。之前敲程式碼的時候偶爾也有這種需求,之前的解決方法是利用 crontab,定時執行某些操作,但是放在這裡就不合適了,因為這裡的任務是實時生成的,且只需要執行一次,而不是定時執行。不過順著之前的思路,我發現了有一個東西說不定能夠滿足我的需求——crontab 的好朋友,at。at 和 crontab 的區別基本上就是,crontab 是週期性的,而 at 是一次性的。

本來喜氣洋洋的,以為這麼快就找到解決方法了,沒想到用著用著發現了一個很致命的問題:at 只支援兩種生成方式,一是先寫一個 bash 指令碼,然後新增到臨時任務裡去,大概像這樣:

at -f commandFile now + 10 minutes

第二種方式是,在命令列中輸入 at now + 10 minutes,然後再輸入具體的指令,形成臨時任務。

我尋尋覓覓了好久,仍然找不到能夠通過 PHP 生成 at 臨時任務的辦法,奈何時間有限,只能放棄這個方法,另尋他徑了。

我找到的第二個方法是 ThinkPHP5(我使用 PHP 框架)使用官方的外掛 think-queue,在稍微瞭解了一下之後,覺這個東西非常不錯,功能好像還蠻強大的,而且挺符合我目前的需求的,但是萬萬沒想到,當我真正跑去用它的時候,出現了那麼多的問題。第一,它的安裝還挺麻煩的,一開始以為直接用 composer require 一下就可以了,結果還有版本問題,支援 TP5 的之有比較老的一些版本。第二,使用起來還是有點迷的,一方面是既沒有找到官方的文件手冊,沒有找到合適的使用教程,另一方面是但是時間比較著急,沒能靜下心來研究。不過感覺這東西好像還是不錯的,等這段時間期末考完了,打算再去認真研究研究。

上面兩種方法皆宣告失敗之後,我只能使用最最原始的辦法了。話不多說,直接上程式碼吧:

//清除之前的緩衝內容
ob_end_clean();
//設定響應頭連線狀態為關閉
header("Connection: close");
//設定HTTP請求狀態為200 OK
header("HTTP/1.1 200 OK");
//返回資料格式
header("Content-Type: application/json;charset=utf-8");
//開啟輸出控制緩衝
ob_start();
//返回資料給前端
echo json_encode($array);
//下面輸出http的一些頭資訊
$size = ob_get_length
(); //返回輸出緩衝區內容的長度 header("Content-Length: $size"); //輸出當前緩衝,並關閉緩衝 ob_end_flush(); //輸出PHP緩衝 flush(); //前端接收到資料,請求到此結束,之後的程式碼都在後臺靜默執行,前端也無法知道執行情況 if (function_exists("fastcgi_finish_request")) { // yii或yaf預設不會立即輸出,加上此句即可(前提是用的fpm) fastcgi_finish_request(); // 響應完成, 立即返回到前端,關閉連線 } //設定客戶端斷開連線時是否中斷指令碼的執行 ignore_user_abort(true); //設定請求時間為不限時 set_time_limit(0); ...這裡寫需要後臺執行的程式碼 //沖刷(flush)所有響應的資料給客戶端,請求完全結束 fastcgi_finish_request();

還是原始的辦法好使,沒遇到啥困難就把問題給解決了,但是總感覺這樣子實現起來太醜了,等有空了還是再去找找更好的辦法吧,暫時就這樣應付一下好了。

另外,如果你有興趣,或者是有問題想要與我探討,歡迎來訪問我的部落格:https:mu-mu.cn/blog