阅读(4258) (9)

Laravel 8 任务中间件

2021-07-06 09:24:59 更新

任务中间件允许你围绕排队任务的执行封装自定义逻辑,从而减少了任务本身的样板代码。例如,看下面的 handle 方法,它利用了 Laravel 的 Redis 速率限制特性,允许每 5 秒只处理一个任务:

/**
 * 执行任务
 *
 * @return void
 */
public function handle()
{
    Redis::throttle('key')->block(0)->allow(1)->every(5)->then(function () {
        info('获取锁 ...');

        // 处理任务 ...
    }, function () {
        // 无法获取锁 ...

        return $this->release(5);
    });
} 

虽然这段代码是有效的, 但是 handle 方法的结构却变得杂乱,因为它掺杂了 Redis 速率限制逻辑。此外,其他任务需要使用速率限制的时候,只能将限制逻辑复制一次。

我们可以定义一个处理速率限制的任务中间件,而不是在 handle 方法中定义速率限制。Laravel 没有任务中间件的默认位置,所以你可以将任务中间件放置在你喜欢的任何位置。在本例中,我们将把中间件放在 app/Jobs/Middleware 目录:

<?php

namespace App\Jobs\Middleware;

use Illuminate\Support\Facades\Redis;

class RateLimited
{
    /**
     * 让队列任务慢慢执行
     *
     * @param  mixed  $job
     * @param  callable  $next
     * @return mixed
     */
    public function handle($job, $next)
    {
        Redis::throttle('key')
                ->block(0)->allow(1)->every(5)
                ->then(function () use ($job, $next) {
                    // 获取锁 ...

                    $next($job);
                }, function () use ($job) {
                    // 无法获取锁 ...

                    $job->release(5);
                });
    }
} 

正如你看到的,类似于 路由中间件,任务中间件接收一个被生成的任务以及一个为了任务被继续进行而需要被注入的回调。

在任务中间件被创建以后,他们可能被关联到通过从任务的 middleware 方法返回的任务。这个方法并不存在于 make:job Artisan 命令搭建的任务中,所以你需要将它添加到你自己的任务类的定义中:

use App\Jobs\Middleware\RateLimited;

/**
 * 获取一个可以被传递通过的中间件任务
 *
 * @return array
 */
public function middleware()
{
    return [new RateLimited];
}