CentOS 下管理自定義 PHP 計劃任務代碼的守護進程腳本

from http://micate.me/centos-php-crontab-script-manage-shell.note
« javascript dialog 對話框的問題總結MySQL的表分區 »CentOS 下管理自定義 PHP 計劃任務代碼的守護進程腳本
Version: 2011-12-05 Print Published at 02:45 in 技術. 2 Comments
Tags: centos, php, 計劃任務.
有需求想實現比 crontab 更頻繁一點的計劃任務,折騰一通之後,寫下這個腳本,目前在 CentOS 6 下測試沒有問題:

ChangeLog
2011.12.05
添加 PHP 執行用戶設置,用以適應如在計劃任務中執行生成文件操作時的文件權限問題,未完成;
2011.12.02
建立文檔;
Shell 代碼
#!/bin/bash
#
# chkconfig: 35 90 12
# description: Queue Daemon
#

# Get function from functions library
. /etc/init.d/functions

# PHP 訪問路徑,如果 PHP 是編譯安裝則需要修改
php_path="/usr/bin/php"

# PHP 執行用戶名
# Nginx 環境下常見爲 nginx 或 www,
# Apapche 環境下常見爲 php 或 apache
# 用在某些時候需要在計劃任務中生成文件時文件權限不正確的問題
php_user=nginx

# 要管理的 PHP 計劃任務腳本
# 該目錄下必須都是 PHP 可執行代碼文件
queue_path="/www/micate.dev/crontab/"

# PHP 計劃任務執行日誌保存路徑
# 默認以 腳本名.log 的方式存儲
log_path="/var/log/queue/"

# 守護進程 PID 路徑
pid_path="/var/run/queued.pid"

# 守護進程在啓動退出時的提示名稱
prog="Queued"

# Start the service
start() {
echo -n $"Starting $prog: "

if [ -f $pid_path ]; then
echo -n "pid "$pid_path" exists."
failure
echo
return 0
fi

if [ ! -d $log_path ]; then
mkdir -p $log_path
fi

queues=$(ls $queue_path)
for queue in $queues
do
# TODO sudo -u $php_user
nohup $php_path $queue_path$queue 1>>$log_path$queue.log 2>/dev/null &
retval=$?
if [ ! $retval -eq 0 ]; then
echo -n $queue" init failed."
failure
echo
return 0
fi
echo $! >> $pid_path
done

success
echo
return $retval
}

# Stop the service
stop() {
echo -n $"Stopping $prog: "

if [ ! -f $pid_path ]; then
echo -n "pid "$pid_path" not exists."
failure
echo
return 0
fi

queues=$(cat $pid_path)
for queue in $queues
do
kill -9 $queue 1>/dev/null 2>&1
retval=$?
if [ ! $retval -eq 0 ]; then
echo -n $queue" stop failed."
failure
echo
return 0
fi
done

rm -f $pid_path

success
echo
return $retval
}

### main logic ###
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
*)
echo $"Usage: $0 {start|stop|restart}"
exit 1
esac

exit 0
使用方法
1.根據實際情況,按照上面的配置提示,修改相應配置,並保存爲 /etc/init.d/queued(建議以這樣的方式命名,注意路徑必須是 /etc/init.d/)
2.在 Shell 裏面執行:

# 爲守護進程腳本增加執行權限
chmod +x /etc/init.d/queued
# 設置開機啓動
chkconfig queued on守護進程設置完成。

3.在上面配置的目錄中添加測試 PHP 計劃任務腳本,如 hello.php:

<?php
// 注意,推薦使用死循環的方式
// 這個守護進程腳本也是以這個思路來寫的
while (true)
{
// 做點事情

// 注意,這裏的輸出會記錄到日誌文件裏面,可以輸出些有用的信息來幫助排除問題
echo "hello from queued.\n";

// 延遲時間,建議用秒級別的,usleep ... 你確定麼?
sleep(20);
}4.好了,來運行看看:

/etc/init.d/queued start查看下日誌目錄:

less /var/log/queue/hello.php.log收工。

其他的,比如:

# 停止所有計劃任務
/etc/init.d/queued stop

# 重新啓動守護進程腳本
/etc/init.d/queued restart注意事項
1.由於是基於死循環的方式實現,如果代碼裏面有引入基礎文件後的死循環操作,那依賴基礎文件中的變量的代碼部分,要注意調整,舉例來說:

<?php
define('START_TIME', microtime(true));

// 假如這個文件裏面定義了 TIME 常量,
// 以備後面的代碼獲取當前時間用
//(避免一次請求中多次調用 time() 函數帶來的性能損失)
require '../init.php';

$interval = value(config('mail'), 'interval', 20);
$interval_size = value(config('mail'), 'interval_size', 50);
while (true)
{
$queue = & factory::queue('mail');

// 這裏的定時循環,用到了 TIME 常量
// 比如記錄執行時間,甚至用 TIME 常量做查詢條件
echo $queue->interval($interval_size);
sleep($interval);
}看了上面的註釋,問題就比較明顯了。
當以普通用戶請求過去時,由於是正常流程,每次請求發起後,TIME 都會重新賦予正確的當前時間;
但當使用死循環後,以後的每次 interval 用到的時間都會是 該計劃任務腳本啓動時間。
這就是問題,需要注意和調整。

2.修改和添加計劃任務後,需要重新啓動守護進程,方法上面已經介紹了,restart 就可以。
3.擔心日誌過多?設置下日誌自動滾動切割吧:

# 在 /etc/logrotate.d/ 目錄下建立 queued 文件
vim /etc/logrotate.d/queued

# 輸入如下的信息,路徑之類的要和你自己設置的保持一致
/var/log/queue/*log {
daily
rotate 10
missingok
notifempty
sharedscripts
compress
postrotate
/etc/init.d/queued restart > /dev/null 2>/dev/null || true
endscript
}保存文件,完成。
這樣,每天日誌會自動滾動切割,最多保留 10 個日誌文件(未驗證這個步驟... 如有問題請反饋)。

4.進程崩潰、服務器斷電...導致守護進程起不來或停不了了?
直接 ps -ef | grep *** 關鍵詞,看是否有在運行的 PHP 計劃任務代碼,kill 掉,然後刪除 pid 文件,重新啓動即可。
更多...
其實 crontab 也有對應的解決方法:

# 打開 crontab 編輯界面
crontab -e

# 輸入類似的設置
* * * * * /bin/date
* * * * * sleep 20; /bin/date
* * * * * sleep 40; /bin/date思想就是... 同時添加多個任務,然後每個之前以適當的延時隔離開,就是說每分鐘會有 N 個程序被觸發,但會逐個延遲執行,也是個不錯的解決思路。


相關文章:
■在 Windows 主機上定時備份遠程 VPS(CentOS) 數據
■在 CentOS 6 環境中配置 nginx + php-fpm + mysql
■Schtasks 計劃任務參數詳解
■關閉 selinux 和使其立即生效
■CentOS 5 修改系統時區

2 Responses to “CentOS 下管理自定義 PHP 計劃任務代碼的守護進程腳本”
Feed for this Entry Trackback Address

--------------------------------------------------------------------------------

蠻-com
2011/12/05 at 13:21
死循環的php-fpm會不會有問題啊啊啊?

Reply
龍貓
2011/12/05 at 16:27
@楊哥(http://www.yanghengfei.com/) 提到,死循環中的 PHP 是不會釋放變量的內存的,一直循環下去,如果代碼上稍不注意,有可能... 內存爆掉。

但這個跟 PHP-FPM 沒關係吧... 調用的是 /usr/bin/ 下的 php,PHP-FPM 在 /usr/sbin/ 下,和 Nginx 木有交互哦。

準備來個 V2,用 shell 死循環代替 PHP 死循環,但我覺得問題會是... 循環時間過短導致下次循環開始時,上次的還沒執行完。判斷進程名稱?寫出來再說吧。

Reply
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章