鍍金池/ 教程/ PHP/ 隊(duì)列
Laravel Cashier
Eloquent ORM
HTTP 響應(yīng)
發(fā)行說明
擴(kuò)展包開發(fā)
HTTP 控制器
事件
擴(kuò)展框架
Contracts
開發(fā)
配置
表單驗(yàn)證
錯(cuò)誤與日志
Hashing
貢獻(xiàn)指南
郵件
Session
遷移與數(shù)據(jù)填充
查詢構(gòu)造器
Redis
升級(jí)向?qū)?/span>
概覽
緩存
服務(wù)提供者
Envoy 任務(wù)執(zhí)行器
隊(duì)列
單元測(cè)試
服務(wù)容器
文件系統(tǒng) / 云存儲(chǔ)
認(rèn)證
請(qǐng)求的生命周期
加密
模板
視圖 (View)
Laravel Homestead
Laravel 安裝指南
介紹
Command Bus
分頁(yè)
輔助方法
應(yīng)用程序結(jié)構(gòu)
HTTP 路由
HTTP 請(qǐng)求
基本用法
本地化
HTTP 中間件
結(jié)構(gòu)生成器
Facades
Laravel Elixir

隊(duì)列

設(shè)置

Laravel 隊(duì)列組件提供一個(gè)統(tǒng)一的 API 集成了許多不同的隊(duì)列服務(wù),隊(duì)列允許你延后執(zhí)行一個(gè)耗時(shí)的任務(wù),例如延后至指定的時(shí)間才發(fā)送郵件,進(jìn)而大幅的加快了應(yīng)用程序處理請(qǐng)求的速度。

隊(duì)列的配置文件在config/queue.php,在這個(gè)文件你將可以找到框架中每種不同的隊(duì)列服務(wù)的連接設(shè)置,其中包含了BeanstalkdIronMQ、Amazon SQS、Redisnull,以及同步 (本地端使用) 驅(qū)動(dòng)設(shè)置。驅(qū)動(dòng)null 只是簡(jiǎn)單的舍棄隊(duì)列工作,因此那些工作永遠(yuǎn)不會(huì)執(zhí)行。

隊(duì)列數(shù)據(jù)表

為了能夠使用database 驅(qū)動(dòng),你需要建立一個(gè)數(shù)據(jù)表來保存工作。要使用一個(gè)遷移建立這個(gè)數(shù)據(jù)表,可以執(zhí)行queue:table Artisan 命令:

php artisan queue:table

其他隊(duì)列依賴

下面的依賴是使用對(duì)應(yīng)的隊(duì)列驅(qū)動(dòng)所需的擴(kuò)展包:

  • Amazon SQS:aws/aws-sdk-php
  • Beanstalkd:pda/pheanstalk ~3.0
  • IronMQ:iron-io/iron_mq ~1.5
  • Redis:predis/predis ~1.0

基本用法

推送一個(gè)工作至隊(duì)列

應(yīng)用程序中能夠放進(jìn)隊(duì)列的工作都存放在App\Commands 目錄下,你可以借由下面 Artisan 命令產(chǎn)生一個(gè)可使用隊(duì)列的命令:

php artisan make:command SendEmail --queued

要推送一個(gè)新的工作至隊(duì)列,請(qǐng)使用Queue::push 方法:

Queue::push(new SendEmail($message));

注意: 在這個(gè)例子當(dāng)中,我們直接使用Queue Facade,然而,常見的作法是借由Command Bus 去分派隊(duì)列命令。我們將會(huì)在這篇文章中繼續(xù)使用Queue Facade,不過,也要熟悉使用 command bus,因?yàn)樗軌蛲瑫r(shí)分派你的網(wǎng)站應(yīng)用程序中隊(duì)列與同步的命令。

默認(rèn)情況下,make:command Artisan 命令會(huì)產(chǎn)生一個(gè) "self-handling" 的命令,意味著命令里會(huì)包含一個(gè)handle 方法。這個(gè)方法將會(huì)在隊(duì)列執(zhí)行時(shí)被調(diào)用。你可以在handle 方法使用時(shí)提示傳入任何你需要的依賴,而服務(wù)容器 會(huì)自動(dòng)注入他們:

public function handle(UserRepository $users)
{
    //
}

如果你希望你的命令有獨(dú)立的處理類別,你可以在使用make:command 命令時(shí)加上--handler 標(biāo)識(shí)。

php artisan make:command SendEmail --queued --handler

這個(gè)被產(chǎn)生出來的處理類別將會(huì)放在App\Handlers\Commands 目錄下面,并且服務(wù)容器會(huì)自動(dòng)解析。

指定隊(duì)列使用特定連接

你也可指定隊(duì)列工作送至指定的連接:

Queue::pushOn('emails', new SendEmail($message));

發(fā)送相同的數(shù)據(jù)去多個(gè)隊(duì)列工作

如果你需要發(fā)送一樣的數(shù)據(jù)去幾個(gè)不同的隊(duì)列工作,你可以使用Queue::bulk 方法:

Queue::bulk(array(new SendEmail($message), new AnotherCommand));

延遲執(zhí)行一個(gè)工作

有時(shí)候你可能想要延遲執(zhí)行一個(gè)隊(duì)列工作,舉例來說你希望一個(gè)隊(duì)列工作在客戶注冊(cè) 15 分鐘后才寄送 e-mail,你可以使用Queue::later 方法來完成這件事情:

$date = Carbon::now()->addMinutes(15);

Queue::later($date, new SendEmail($message));

在這個(gè)例子中,我們使用Carbon 日期類庫(kù)來指定我們希望隊(duì)列工作希望延遲的時(shí)間,另外你也可發(fā)送一個(gè)整數(shù)來設(shè)置你希望延遲的秒數(shù)。

注意: 在 Amazon SQS 服務(wù)中,有最大 900 秒( 15 分鐘 )的限制。

將 Eloquent 模型放進(jìn)隊(duì)列

如果你隊(duì)列工作的構(gòu)造器接收一個(gè) Eloquent 模型,只有這個(gè)模型的標(biāo)記( identifier ) 會(huì)被序列化后放到隊(duì)列中。當(dāng)工作真正開始被處理的時(shí)候,隊(duì)列系統(tǒng)會(huì)自動(dòng)從數(shù)據(jù)庫(kù)中重新取得完整的模型實(shí)例。這個(gè)對(duì)你的網(wǎng)站應(yīng)用程序來說是完全透明的,并且預(yù)防一些在序列化完整 Eloquent 模型實(shí)例時(shí)可能遇到的問題。

刪除一個(gè)處理中的工作

一旦一個(gè)工作被處理過后,這個(gè)工作必須從隊(duì)列中刪除。假如在工作執(zhí)行后沒有發(fā)生錯(cuò)誤,這個(gè)將會(huì)自動(dòng)完成。

如果你希望能夠手動(dòng)刪除或著釋放工作,在Illuminate\Queue\InteractsWithQueue trait 中提供release 以及delete 方法的接口。其中release 方法接受單一一個(gè)值:你想要等待工作再次能夠執(zhí)行的秒數(shù)。

public function handle(SendEmail $command)
{
    if (true)
    {
        $this->release(30);
    }
}

釋放一個(gè)工作回到隊(duì)列中

假如在工作執(zhí)行后發(fā)生錯(cuò)誤,這個(gè)工作將會(huì)自動(dòng)被釋放回到隊(duì)列之中,如此一來便能夠再次嘗試執(zhí)行工作。工作會(huì)一直被釋放回隊(duì)列直到到達(dá)應(yīng)用程序的嘗試上限。這個(gè)上限數(shù)值可以在使用queue:listenqueue:work Artisan 命令時(shí)候借由--tries 開關(guān)來設(shè)置。

檢查工作執(zhí)行次數(shù)

當(dāng)一個(gè)工作執(zhí)行后發(fā)生錯(cuò)誤,這個(gè)工作將會(huì)自動(dòng)的釋放回隊(duì)列當(dāng)中,你可以透過attempts 方法來檢查這個(gè)工作已經(jīng)被執(zhí)行的次數(shù):

if ($this->attempts() > 3)
{
    //
}

注意: 你的命令處理類別必須使用Illuminate\Queue\InteractsWithQueue 這個(gè) trait 才能夠使用這個(gè)方法。

隊(duì)列閉包

你也可以推送一個(gè)閉包去隊(duì)列,這個(gè)方法非常的方便及快速的來處理需要使用隊(duì)列的簡(jiǎn)單的任務(wù):

推送一個(gè)閉包至隊(duì)列

Queue::push(function($job) use ($id)
{
    Account::delete($id);

    $job->delete();
});

注意: 要讓一個(gè)組件變量可以在隊(duì)列閉包中可以使用我們會(huì)通過use 命令,試著發(fā)送主鍵及重復(fù)使用的相關(guān)模塊在你的隊(duì)列工作中,這可以避免其他的序列化行為。

當(dāng)使用 Iron.iopush queues 時(shí),你應(yīng)該在隊(duì)列閉包中采取一些其他的預(yù)防措施,我們應(yīng)該在執(zhí)行工作收到隊(duì)列數(shù)據(jù)時(shí)檢查token是否真來自 Iron.io,舉例來說你推送一個(gè)隊(duì)列工作到https://yourapp.com/queue/receive?token=SecretToken,接下來在你的工作收到隊(duì)列的請(qǐng)求時(shí),你就可以檢查token的值是否正確。

執(zhí)行一個(gè)隊(duì)列監(jiān)聽

Laravel 內(nèi)含一個(gè) Artisan 命令,它將推送到隊(duì)列的工作拉來下執(zhí)行,你可以使用queue:listen 命令,來執(zhí)行這件常駐任務(wù):

開始隊(duì)列監(jiān)聽

php artisan queue:listen

你也可以指定特定隊(duì)列連接讓監(jiān)聽器使用:

php artisan queue:listen connection

注意當(dāng)這個(gè)任務(wù)開始時(shí),這將會(huì)一直持續(xù)執(zhí)行到他被手動(dòng)停止,你也可以使用一個(gè)處理監(jiān)控如Supervisor 來確保這個(gè)隊(duì)列監(jiān)聽不會(huì)停止執(zhí)行。

你也可以在listen 命令中使用逗號(hào)分隔的隊(duì)列連接,來設(shè)置不同隊(duì)列連接的優(yōu)先層級(jí):

php artisan queue:listen --queue=high,low

在這個(gè)范列中,總是會(huì)優(yōu)先處理high-connection 中的工作,然后才處理low-connection。

指定工作超時(shí)參數(shù)

你也可以設(shè)置給每個(gè)工作允許執(zhí)行的秒數(shù):

php artisan queue:listen --timeout=60

指定隊(duì)列休息時(shí)間

此外,你也可以指定讓監(jiān)聽器在拉取新工作時(shí)要等待幾秒:

php artisan queue:listen --sleep=5

注意隊(duì)列只會(huì)在工作時(shí)休息,假如有許多可執(zhí)行的工作,隊(duì)列會(huì)持續(xù)的處理工作而不會(huì)休息

處理隊(duì)列上的第一個(gè)工作

當(dāng)你只想處理隊(duì)列上的一個(gè)工作你可以使用queue:work Artisan 命令:

php artisan queue:work

常駐隊(duì)列處理器

queue:work 中也包含了一個(gè)--daemon 選項(xiàng),強(qiáng)迫隊(duì)列處理器持續(xù)處理工作,而不會(huì)每次都重新啟動(dòng)框架,這個(gè)作法比起queue:listen 可有效減少 CPU 使用量,但是卻增加了布署時(shí),對(duì)于處理中隊(duì)列任務(wù)的復(fù)雜性。

要啟動(dòng)一個(gè)常駐的隊(duì)列處理器,使用--daemon

php artisan queue:work connection --daemon

php artisan queue:work connection --daemon --sleep=3

php artisan queue:work connection --daemon --sleep=3 --tries=3

如你所見queue:work 命令支持queue:listen 大多相同的選項(xiàng)參數(shù),你也可使用php artisan help queue:work 命令來觀看全部可用的選項(xiàng)參數(shù)。

布署常駐隊(duì)列處理器

最簡(jiǎn)單布署一個(gè)應(yīng)用程序使用常駐隊(duì)列處理器的方式,就是將應(yīng)用程序在開始布署時(shí)轉(zhuǎn)成維護(hù)模式,你可以使用php artisan down 命令來完成這件事情,當(dāng)這個(gè)應(yīng)用程序在維護(hù)模式,Laravel 將不會(huì)允許任何來自隊(duì)列上的新工作,但會(huì)持續(xù)的處理已存在的工作。

要重新啟動(dòng)queue 也是非常容易,請(qǐng)將底下命令加到部署命令:

php artisan queue:restart

上述命令會(huì)在執(zhí)行完目前的工作后,重新啟動(dòng)隊(duì)列。

注意: 這個(gè)命令依賴緩存系統(tǒng)來排定重新啟動(dòng)任務(wù)。默認(rèn) APCu 無法在命令提示字符中工作。如果你正在使用 APCu 請(qǐng)將apc.enable_cli=1 加到你的 APCu 設(shè)置當(dāng)中。

撰寫常駐隊(duì)列處理器

常駐隊(duì)列處理器不會(huì)在處理每一個(gè)工作之前都重新啟動(dòng)框架。因此,你應(yīng)該注意并小心地在工作處理完成之前釋放占用的資源。例如,如果你正在使用 GD 函式庫(kù)操作圖片,當(dāng)你完成工作的時(shí)候,你應(yīng)該使用imagedestroy 方法來釋放占用的內(nèi)存。

同樣地,數(shù)據(jù)庫(kù)連接可能在長(zhǎng)時(shí)間執(zhí)行的隊(duì)列處理器中斷線,你可以使用DB::reconnect 方法來確保你每次都有一個(gè)全新的連接。

推送隊(duì)列

你可以利用強(qiáng)大的 Laravel 5 隊(duì)列架構(gòu)來進(jìn)行推送隊(duì)列工作,不需要執(zhí)行任何的常駐或背景監(jiān)聽,目前只支持Iron.io 驅(qū)動(dòng),在你開始前建立一個(gè) Iron.io 帳號(hào)及添加你的 Iron 憑證到config/queue.php 配置文件。

注冊(cè)一個(gè)推送隊(duì)列訂閱

接下來,你可以使用queue:subscribe Artisan 命令注冊(cè)一個(gè) URL,這將會(huì)接收新的推送隊(duì)列工作:

php artisan queue:subscribe queue_name http://foo.com/queue/receive

現(xiàn)在當(dāng)你登錄你的 Iron 管理后臺(tái),你將會(huì)看到你新的推送隊(duì)列,以及訂閱的 URL,你可以訂閱許多的 URLs 給你希望的隊(duì)列,接下來建立一個(gè) route 給你的queue/receive 及從Queue::marshal 方法回傳回應(yīng):

Route::post('queue/receive', function()
{
    return Queue::marshal();
});

這里的marshal 方法會(huì)將觸發(fā)正確的處理類別,而發(fā)送工作到隊(duì)列中只要使用一樣的Queue::push 方法。

已失敗的工作

事情往往不會(huì)如你預(yù)期的一樣,有時(shí)候你推送工作到隊(duì)列會(huì)失敗,別擔(dān)心,Laravel 包含一個(gè)簡(jiǎn)單的方法去指定一個(gè)工作最多可以被執(zhí)行幾次,在工作被執(zhí)行到一定的次數(shù)時(shí),他將會(huì)添加至failed_jobs 數(shù)據(jù)表里,然后失敗工作的數(shù)據(jù)表名稱可以在config/queue.php 里進(jìn)行設(shè)置:

要產(chǎn)生一個(gè)遷移來建立failed_jobs 數(shù)據(jù)表,你可以使用queue:failed-table Artisan 命令:

php artisan queue:failed-table

你可以指定一個(gè)最大值來限制一個(gè)工作應(yīng)該最多被執(zhí)行幾次,在你執(zhí)行queue:listen 時(shí)加上--tries

php artisan queue:listen connection-name --tries=3

假如你會(huì)想注冊(cè)一個(gè)事件,這個(gè)事件會(huì)將會(huì)在隊(duì)列失敗時(shí)被調(diào)用,你可以使用Queue::failing 方法,這個(gè)事件是一個(gè)很好的機(jī)會(huì)讓你可以通知你的團(tuán)隊(duì)通過 e-mail 或HipChat。

Queue::failing(function($connection, $job, $data)
{
    //
});

你可能夠直接在隊(duì)列工作類別中定義一個(gè)failed 方法,這讓你能夠在工作失敗時(shí)候,執(zhí)行一些特定的動(dòng)作:

public function failed()
{
    // 當(dāng)工作失敗的時(shí)候會(huì)被調(diào)用……
}

重新嘗試失敗的工作

要看到所有失敗的工作,你可以使用queue:failed 命令:

php artisan queue:failed

這個(gè)queue:failed 命令將會(huì)列出工作 ID、連接、隊(duì)列名稱及失敗的時(shí)間,可以使用工作 ID 重新執(zhí)行一個(gè)失敗的工作,例如一個(gè)已經(jīng)失敗的工作的 ID 是 5,我們可以使用下面的命令:

php artisan queue:retry 5

假如你想刪除一個(gè)失敗的工作,可以使用queue:forget 命令:

php artisan queue:forget 5

要?jiǎng)h除全部失敗的工作,可以使用queue:flush 命令:

php artisan queue:flush
上一篇:視圖 (View)下一篇:HTTP 請(qǐng)求