当咱们的系统触发了一个延迟任务,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