本例使用redis作为队列驱动。
1、config/queue.php
connections
'redis' => [
'driver' => 'redis',
'connection' => env('QUEUE_REDIS_CONNECTION', 'default'),
'queue' => 'default',// 队列名
'retry_after' => 90,// 单个任务被执行最大时间,超过这个时间将被重新放回队列
'block_for' => null,
],
配置env文件
QUEUE_CONNECTION=redis 也可在投递的时候指定
QUEUE_REDIS_CONNECTION=default 其实默认的就是default可不设置
对应就是database.php中redis下的连接标识。
2、app/Jobs/Job.php
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
abstract class Job implements ShouldQueue
{
/*
|--------------------------------------------------------------------------
| Queueable Jobs
|--------------------------------------------------------------------------
|
| This job base class provides a central location to place any logic that
| is shared across all of your jobs. The trait included with the class
| provides access to the "queueOn" and "delay" queue helper methods.
|
*/
use InteractsWithQueue, Queueable, SerializesModels;
}
3、app/Jobs/Read3Job.php
<?php
namespace App\Jobs;
use Exception;
class Read3Job extends Job
{
public $data;
public function __construct(...$data)
{
$this->data = $data;
}
public function handle()
{
var_dump($this->data);
}
public function failed(Exception $exception)
{
// 给用户发送失败的通知等等...
}
}
依赖主入放在handle()参数里
4、投递任务
use App\Jobs\Read3Job;
public function test(){
$data = [
'activity_id' => 1,
'userid' => 1,
'reach' => 1,
'from_type' => 1,
];
$conf = [
'conf_id' => 1,
];
// 指定连接,指定队列名
dispatch(new Read3Job($data, $conf))->onConnection('redis')->onQueue('read3');
return;
}
5、调用test方法,查看redis里面是否有queues生成。
6、消费
CMD
进入项目根目录
php artisan queue:work redis --queue=read3 --tries=3
可见打印出的信息,同时redis中该元素已被删除。
但是此时命令行关闭就会退出进程。
7、消费进程部署优化
查看帮助 php artisan help queue:work
发现有一个–daemon参数可以作为后台进程启动
–daemon Run the worker in daemon mode (Deprecated
),表示不推荐这么做!!
所以还是采用手动的方式开启后台进程吧。
`nohup php artisan queue:work redis --queue=read3 --tries=3 > /dev/null 2>&1 &`
在当前的队列任务执行完毕后, 重启队列的守护进程:`php artisan queue:restart`
这是相对于你使用 --daemon 参数来启动守护进程的,不包括你手动启动的守护进程,既然官方并不支持使用
--daemon 参数,并且我测试的效果也不理想,所以 restart 的功能就只剩下停止进程了。
这个命令将会引导`所有的队列处理器`在完成当前任务后平滑「中止」,这样不会有丢失的任务,`目前并不支持终止某
一个队列`。
由于在执行 queue:restart 后队列处理器都将会退出,所以你应该运行一个进程管理器,例如 Supervisor
来自动重启队列处理器。{tip} 队列使用 缓存 存储重启信号,所以你应该确定在使用这个功能之前配置好缓存驱动。
如果代码发生改动,使用`php artisan queue:restart`来停止进程,然后supervisor会自动唤起进程,千万不要使
用kill或者supervisor来停止进程,会导致数据异常。
具体参考Laravel文档:https://learnku.com/docs/laravel/5.7/queues/2286#supervisor-configuration
8、处理失败的任务
有时你的队列任务会失败。别担心,凡事无完美! Laravel 包含了一个便捷的方式指定任务会被最大尝试的次数。在一个任务达到了它最大尝试次数后,它会被放入 failed_jobs 表。要创建 failed_jobs 表你可以使用:
// 创建数据表定义文件,在database/migrantions/下面
php artisan queue:failed-table
// 建表
php artisan migrate
数据库多了两个表 migrations,failed_jobs
然后,运行你的 队列处理器 ,你应该在 queue:work 命令上使用 --tries 选项。如果你没有指定 --tries 的
值,任务将会被无限次尝试。
php artisan queue:work redis --queue=read3 --tries=3
然后可以在Read3Job的failed方法中做一些保持数据一致性的操作
注意!!!
那么,如何判断任务失败呢,其实只有发生系统错误或者我们在业务里抛出了异常就会被判断为失败。
还有,如果你自己try…catch 捕获了异常,那么异常就无法透传到框架底层,自然框架就不会判定为失败,因为底层就是try…catch来捕获异常从而判断是否是失败。因此,如果要自定义失败逻辑的话,自己先捕获,然后要再次抛出给底层。
public function handle()
{
try {
$this->dailyTaskAction();
} catch (\Exception $e) {
Log::info('队列任务处理失败1:' . $e->getMessage());
Log::info('队列任务处理失败1:' . json_encode([$this->data, $this->conf]));
throw new \Exception($e->getMessage());// 抛给底层
}
}
9、失败任务的处理
对于存在 failed_jobs 表的失败任务
查看:php artisan queue:failed
queue:failed 命令会列出任务 ID ,队列,以及失败的时间。任务 ID 可能会被用于重试失败的任务。例如,要重试一个任务 ID 为 5 的任务,使用如下命令:
重试一个任务:php artisan queue:retry 5
要重试所有失败的任务:php artisan queue:retry all
删除一个失败的任务:php artisan queue:forget 5
清空所有失败的任务:php artisan queue:flush
注意,这些重试命令只是将任务重新投入队列了,并不是消费了!!!