當咱們的系統觸發了一個延遲任務,Laravel會用當前的時間加上任務的延遲時間計算出任務的執行時間戳,而後將這個時間戳和任務信息序列化以後存入隊列,,Laravel 的隊列處理器會不斷查詢並執行隊列中知足預計執行時間等於或早於當前時間的任務。php
咱們經過 make:job
命令來建立一個任務:
redis
php artian make:job CloseOrder複製代碼
建立的任務類保存在 app/Jobs
目錄下,如今編輯剛剛建立的任務類:sql
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use App\Models\Order;
// 表明這個類須要被放到隊列中執行,而不是觸發時當即執行
class CloseOrder implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $order;
public function __construct(Order $order, $delay)
{
$this->order = $order;
// 設置延遲的時間,delay() 方法的參數表明多少秒以後執行
$this->delay($delay);
}
// 定義這個任務類具體的執行邏輯
// 當隊列處理器從隊列中取出任務時,會調用 handle() 方法
public function handle()
{
// 判斷對應的訂單是否已經被支付
// 若是已經支付則不須要關閉訂單,直接退出
if ($this->order->paid_at) {
return;
}
// 經過事務執行 sql
\DB::transaction(function() {
// 將訂單的 closed 字段標記爲 true,即關閉訂單
$this->order->update(['closed' => true]);
// 循環遍歷訂單中的商品 SKU,將訂單中的數量加回到 SKU 的庫存中去
foreach ($this->order->items as $item) {
$item->productSku->addStock($item->amount);
}
});
}
}複製代碼
接下來咱們須要在建立訂單以後觸發這個任務:bash
use App\Jobs\CloseOrder;
.
.
.
public function store(Request $request)
{
.
.
.
$this->dispatch(new CloseOrder($order, config('app.order_ttl')));
return $order;
}複製代碼
CloseOrder
構造函數的第二個參數延遲時間咱們從配置文件中讀取,爲了方便咱們測試,把這個值設置成 30 秒:
app
'order_ttl' => 30,複製代碼
默認狀況下,Laravel 生成的 .env
文件裏把隊列的驅動設置成了 sync
(同步),在同步模式下延遲任務會被當即執行,因此須要先把隊列的驅動改爲 redis
:
composer
.
.
.
QUEUE_CONNECTION=redis
.
.
.複製代碼
要使用 redis
做爲隊列驅動,咱們還須要引入 predis/predis
這個包
函數
composer require predis/predis複製代碼
接下來啓動隊列處理器:
測試
php artisan queue:work複製代碼
切記:若是測試中途要修改定時任務執行程序的內容,必須先中止隊列,更改完過後重啓隊列。ui