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

隊(duì)列

設(shè)置

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

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

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

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

php artisan queue:table

其他隊(duì)列依賴

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

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

基本用法

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

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

php artisan make:command SendEmail --queued

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

刪除一個處理中的工作

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

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

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

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

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

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

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

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

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

隊(duì)列閉包

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

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

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

    $job->delete();
});

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

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

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

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

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

php artisan queue:listen

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

php artisan queue:listen connection

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

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

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

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

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

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

php artisan queue:listen --timeout=60

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

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

php artisan queue:listen --sleep=5

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

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

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

php artisan queue:work

常駐隊(duì)列處理器

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

要啟動一個常駐的隊(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ì)列處理器

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

要重新啟動queue 也是非常容易,請將底下命令加到部署命令:

php artisan queue:restart

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

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

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

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

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

推送隊(duì)列

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

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

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

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

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

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

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

已失敗的工作

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

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

php artisan queue:failed-table

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

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

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

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

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

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

重新嘗試失敗的工作

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

php artisan queue:failed

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

php artisan queue:retry 5

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

php artisan queue:forget 5

要刪除全部失敗的工作,可以使用queue:flush 命令:

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