本文實例講述了Laravel框架隊列原理與用法。分享給大家供大家參考,具體如下:
最近有朋友有朋友問laravel隊列的實現原理和經驗,剛好用過所以整理了一下分享給大家。
laravel隊列配置參見:http://d.laravel-china.org/docs/5.1/queues
原理分析
創建分發任務方法
class TestController extends Controller
{
//其他方法
//發送消息
public function SendMessage(Request $request){
...
$this->dispatch((new SendMessage($sendParams))->onQueue('snail:SendMessage'));
}
}
內部實現:

創建消費任務
命令行運行如下命令:
/home/niuyufu/php/bin/php /home/niuyufu/webroot/assistant_api/artisan queue:work --queue=snail:SendMessage --tries=3 --memory=512 --daemon
內部實現:

隊列消息分析:
監控redis對應隊列消息,具體產生的消息操作,如下:
tail -f | redis-cli -h 10.94.120.13 -p 6380 monitor | grep "queues:snail"
1492446053.406282 [0 10.95.117.155:57132] "WATCH" "queues:snail:SendMessage:delayed"
1492446053.406452 [0 10.95.117.155:57132] "ZRANGEBYSCORE" "queues:snail:SendMessage:delayed" "-inf" "1492446053"
1492446053.406754 [0 10.95.117.155:57132] "WATCH" "queues:snail:SendMessage:reserved"
1492446053.406842 [0 10.95.117.155:57132] "ZRANGEBYSCORE" "queues:snail:SendMessage:reserved" "-inf" "1492446053"
1492446053.407029 [0 10.95.117.155:57132] "LPOP" "queues:snail:SendMessage"
1492446053.407700 [0 10.95.117.155:57132] "ZADD" "queues:snail:SendMessage:reserved" "1492446113" "{job}"
1492446053.463953 [0 10.95.117.155:57132] "ZREM" "queues:snail:SendMessage:reserved" "{job}"
PS:如果你的redis是codis的話,注意了,因為codis禁用方法列表
KEYS, MOVE, OBJECT, RENAME, RENAMENX, SORT, SCAN, BITOP,MSETNX, BLPOP, BRPOP, BRPOPLPUSH, PSUBSCRIBE,PUBLISH, PUNSUBSCRIBE, SUBSCRIBE, UNSUBSCRIBE, DISCARD, EXEC, MULTI, UNWATCH, WATCH, SCRIPT EXISTS, SCRIPT FLUSH, SCRIPT KILL, SCRIPT LOAD, AUTH, ECHO, SELECT, BGREWRITEAOF, BGSAVE, CLIENT KILL, CLIENT LIST, CONFIG GET, CONFIG SET, CONFIG RESETSTAT, DBSIZE, DEBUG OBJECT, DEBUG SEGFAULT, FLUSHALL, FLUSHDB, INFO, LASTSAVE, MONITOR, SAVE, SHUTDOWN, SLAVEOF, SLOWLOG, SYNC, TIME
所以執行消費任務會有以下錯誤:
[Predis\Connection\ConnectionException]
Error while reading line from the server. [tcp://100.90.154.39:3000]
解決方法為修改config/queue.php
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => 'default',
'expire' => null, //禁用即可
],
優化日志處理:
如果你的系統有切割文件日志操作。會發現雖然日志被切分了,但程序卻沒有往新文件里寫入。如,2017-04-18 13:50啟動的項目,日志會一直打到 snail.log.2017041813上。
改進方案:
app/Jobs/Job.php文件中添加如下方法:
public function releaseLoggerFile(){
$handles=\Log::getMonolog()->getHandlers();
if(!is_array($handles) || empty($handles)){
return;
}
foreach($handles as $handle){
if(method_exists($handle, "close")){
$handle->close();
}
}
return;
}
在具體job實現類中的handle方法結尾添加:
public function handle()
{
...
$this->releaseLoggerFile(); //釋放log文件
}
線上部署
創建任務shell
#!/bin/sh
day=$(date +'%y%m%d')
now=$(date +"%F %T")
php_command="/home/niuyufu/php/bin/php"
command="/home/niuyufu/webroot/snail_api/artisan"
log="/home/niuyufu/webroot/log/wave"
queue_name_arr=("snail:SendMessage" "snail:SendMessageToApp")
case $1 in
"run")
for queue_name in ${queue_name_arr[*]}
do
count=$(ps aux | grep artisan |grep queue=${queue_name} | grep -v grep | wc -l)
if [ ${count} -lt 1 ];then
echo "${now}:${queue_name} process has exit ${count}\n";
nohup $php_command $command queue:work --queue=${queue_name} --tries=3 --memory=512 --daemon >> $log/queueMonitor.log 2>1
else
echo "${now}:${queue_name} process is runing";
fi
done
;;
"stop")
kill -9 $(ps -ef | grep "queue:work" | grep -v grep | awk '{print $2}' | tr -s '\n' ' ')
echo ${now}."Queue process all stop";
;;
"list")
ps -ef | grep "queue:work" | grep -v grep
;;
*)
echo "
Usage: QueueMonitorCommandShell.sh [run|stop|list]
"
;;
esac
總結:
laravel這邊的延遲隊列使用了三個隊列。
queue:default:delayed // 存儲延遲任務
queue:default // 存儲"生"任務,就是未處理任務
queue:default:reserved // 存儲待處理任務
任務在三個隊列中進行輪轉,最后一定進入到queue:default:reserved,并且成功后把任務從這個隊列中刪除。
laravel5.1 使用了watch來控制隊列的原子操作,但由于codis本身不支持 watch 方法。所以使用codis不能完全體驗隊列功能:延遲隊列不支持、不支持數據重跑,對線上數據比較嚴格操作謹慎使用。
laravel5.3 之后redis隊列 開始使用lua腳本支持的隊列原子操作,它沒有使用 watch multi等操作,所以如果線上codis 支持lua的話,可以完整體驗到隊列功能。
參考文檔:
https://laravel-china.org/articles/4169/analysis-of-laravel-message-queue
http://laravelacademy.org/post/2012.html
更多關于Laravel相關內容感興趣的讀者可查看本站專題:《Laravel框架入門與進階教程》、《php優秀開發框架總結》、《php面向對象程序設計入門教程》、《php+mysql數據庫操作入門教程》及《php常見數據庫操作技巧匯總》
希望本文所述對大家基于Laravel框架的PHP程序設計有所幫助。
您可能感興趣的文章:- laravel5.6 框架郵件隊列database驅動簡單demo示例
- Laravel使用Queue隊列的技巧匯總
- Docker部署Laravel應用實現隊列&任務調度
- Laravel 6 將新增為指定隊列任務設置中間件的功能
- Laravel 隊列使用的實現
- Laravel中為什么不使用blpop取隊列詳析
- 關于 Laravel Redis 多個進程同時取隊列問題詳解
- 源碼分析 Laravel 重復執行同一個隊列任務的原因
- Laravel使用消息隊列需要注意的一些問題
- Laravel中利用隊列發送郵件的方法示例
- 淺談Laravel隊列實現原理解決問題記錄
- 淺析Laravel5中隊列的配置及使用
- PHP的Laravel框架中使用消息隊列queue及異步隊列的方法
- Laravel 4.2 中隊列服務(queue)使用感受
- Laravel框架中隊列和工作(Queues、Jobs)操作實例詳解