2014-01-18 82 views
1

我正在使用Ubuntu 12上的nginx上運行的PHP網站,它可以在後臺啓動長時間運行的作業。爲什麼在後臺運行PHP進程會導致整個站點掛起?

這個想法是,用戶提交一個表單,它在另一個進程中啓動一個長時間的工作(php_fpm應該處理這個問題),並且如果作業開始或者沒有,立即向用戶返回成功/失敗消息。

也許這是不是做的最好的方法,但是這是我在做什麼:

`php $docroot/longjob.php $this->ID arg2 &> error_log &`; 

($這個 - > ID和ARG2都是簡單的字符串配置工作。)

作業啓動並正常運行,但面向前方的網站會掛起直到作業完成。頁面無法加載,並且服務器在長時間工作完成之前不會響應。我並不期待這一點。爲何會發生這種情況?

更新:所以,我一直在嘗試......不幸的是,關閉會話處理程序並嘗試使用nohop命令並沒有阻止掛起。但它只是對我來說,在我發起請求的機器上。我可以從我的手機登錄,並且該網站可以正常工作,而且它也適用於其他用戶(phew)。任何其他的想法,爲什麼它只會掛在發起請求的機器上?

如果它的事項,這是時顯示的默認nginx的錯誤頁面:

您正在查找的頁面暫時不可用。

請稍後再試。

+3

內置會話save_handler將鎖定會話文件,直到該過程完成並且下一個進程需要等待,直到會話文件解鎖。因此,如果您正在使用會話,則可能需要在啓動長時間運行的作業之前調用session_write_close。 –

+0

@AlexandruG。我確實在使用會話。從來沒有想到這一點。當我有機會並且回報時,我會嘗試的! – Matt

+0

@AlexandruG。不幸的是,使用'session_write_close()不會停止等待。但是,似乎只能從我開始工作的計算機上掛起。所以我想知道是否仍然存在會話問題......或者是nginx/php-fpm做了些什麼... – Matt

回答

1

這是因爲當前的PHP進程等待您執行的命令完成之後纔會繼續。就像我在之前的評論中說的那樣,在開始這個工作之前關閉任何會話,因爲PHP會鎖定會話文件,直到長時間運行的進程結束,下一個進程需要等待,直到會話文件解鎖。

關於該命令的執行方法,我會用nohup的做到這一點,是這樣的:

<?php 
$cmd = "php $docroot/longjob.php $this->ID arg2"; 
exec("/usr/bin/nohup $cmd >/dev/null 2>&1 &"); 

這樣你$cmd將在背景和當前的進程中開始可以繼續他的執行,而不關心它。

+0

我覺得這是正確的軌道,我已經對我的代碼進行了修改,但不幸的是,該網站仍然掛起。雖然我的問題見我的更新。 – Matt

+0

您是否檢查過error_log?您很可能會找到有關導致錯誤的附加信息。 –

0

像這樣的事情發生在我身上的時候,在nginx的和PHP FPM,我有PHP運行是這樣的:

exec("nohup ssh long-running command & >$logfile 2>&1"); 

我可以看到進程ps axfw這樣的:

[...] 
18658 ?  S  0:00 \_ php-fpm: pool www 
18734 ?  Z  0:00 | \_ [sh] <defunct> 
[...] 
18737 ?  S  0:00 ssh long-running command 

一些調試顯示FPM卡住等待命令:

% sudo strace -p 18658 
Process 18658 attached 
read(9, 

% sudo lsof -p 18658 | grep 9r 
php5-fpm 18658 user 9r FIFO    0,8  0t0 9332553 pipe 

% sudo lsof -n | grep 9332553 
php5-fpm 18658  user  9r  FIFO    0,8  0t0 9332553 pipe 
ssh  18737  user  1w  FIFO    0,8  0t0 9332553 pipe 
ssh  18737  user  6w  FIFO    0,8  0t0 9332553 pipe 

這意味着子ssh的兩個文件描述符以某種方式被掛鉤,以便在管道上寫入父項。他們是1 - 標準輸出 - 和6 - 猜測這是遠程命令的標準輸出。

因此很顯然,在嘗試將該stdout重定向到日誌文件時發生了錯誤。解決的辦法是使用更習慣shell語法:

exec("nohup ssh long-running command >$logfile 2>&1 &"); 

這樣一來,通過exec()分叉殼重定向所有的輸出,並把SSH進程在後臺在本地機器上,而不是(顯然)通過與符號到它。

0

對於一個冗長的[背景]過程,我使用這個技巧到我的服務器。 只需等待幾秒鐘,然後可以像平常一樣自由瀏覽其他頁面。

希望有人會得到它非常有幫助。

session_start(); 
isset($_SESSION['id']) or header('Location: ./index.html'.(
    isset($_REQUEST['redir'])? '?redir='.urlencode($_REQUEST['redir']):NULL 
),TRUE)&exit; 

$data= $_SESSION['userdata']; 

/**The session need to be closed when running long process***/ 
session_write_close() & ignore_user_abort(TRUE); 
set_time_limit(0); 

大部分時間我用AJAX異步調用來等待這個頁面的響應。

相關問題