1.1.1. 延迟任务

当触发一个延迟任务时,laravel 会自动换算指定时间戳,将时间戳和任务序列化到队列中,laravel 队列不断查询队列中满足条件的任务。

生成一个任务:

php artisan make:job <job_name>

编辑 app/Jobs/.php

<?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);
            }
        });
    }
}

最终在控制器触发任务即可:

use App\Jobs\CloseOrder;
    .
    .
    .
    public function store(OrderRequest $request)
    {
        .
        .
        .
        // 触发任务
        $this->dispatch(new CloseOrder($order, config('app.order_ttl')));

        return $order;
    }

执行原理

  1. 当触发任务时,laravel 会将任务 zadd 到一个名叫 queues:default:delayed 的 zset 数据结构中。
  2. 然后通过 zrangebyscore 和 zrangebyrank 取出 -inf 到 now 的任务。用 rpush 存入 list 数据结构中。
  3. 然后把 list 队列中的任务 lpop 出来,尝试次数+1
  4. 然后 zadd 到 queues:default:reserved ,程序处理这里面的任务。
  5. 处理完成后删除 queues:default:reserved 的任务。

参考: Laravel 的消息队列剖析 Laravel 基于redis队列的解析

Copyright © Kagami丶 2019 all right reserved,powered by Gitbook该文件修订时间: 2019-10-21 16:00:14

results matching ""

    No results matching ""