Laravel进阶系列笔记--(八)Laravel 基于Reids的消息队列的使用

作者: 温新

分类: 【Laravel】

阅读: 2221

时间: 2021-08-17 13:21:50

作者:温新

时间:2021-07-09

hi,我是温新,一名PHPer。

本篇文章紧接着 Laravel进阶系列笔记--(7)Laravel 基础数据库存储的消息队列的使用 篇文章,两篇文章之前的关系是紧密相连,同时,本篇 Redis消息队列的使用 是基于该篇的操作进行的。

基于Redis的队列任务

第一步:windows下安装Redis数据库与Redis扩展

关于Redis的安装请自行安装。

第二步:修改驱动为Redis

文件:.env

<span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(170, 85, 0)">// 修改redis驱动</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(0, 0, 0)">QUEUE_CONNECTION</span><span style="box-sizing: border-box;color: rgb(152, 26, 26)">=</span><span style="box-sizing: border-box;color: rgb(0, 0, 0)">redis</span></span>

只要把驱动修改为redis,其他的什么都不要动。没错,就是这样的简单,这样的优雅。

修改为Redis驱动,windows中打开Redis服务器与客户端。

第三步:创建任务类

php artisan make:job SendEamilToUser

该命令会在app/Jobs目录下生成SendEamilToUser.php文件。

编辑SendEamilToUser.php文件进行消息队列任务的处理

<span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(152, 26, 26)"><?</span><span style="box-sizing: border-box;color: rgb(0, 0, 0)">php</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(119, 0, 136)">namespace</span> <span style="box-sizing: border-box;color: rgb(0, 0, 255)">App\Jobs</span>;</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(119, 0, 136)">use</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">App\Models\User</span>;</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(119, 0, 136)">use</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">Illuminate\Bus\Queueable</span>;</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(119, 0, 136)">use</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">Illuminate\Contracts\Queue\ShouldBeUnique</span>;</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(119, 0, 136)">use</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">Illuminate\Contracts\Queue\ShouldQueue</span>;</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(119, 0, 136)">use</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">Illuminate\Foundation\Bus\Dispatchable</span>;</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(119, 0, 136)">use</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">Illuminate\Queue\InteractsWithQueue</span>;</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(119, 0, 136)">use</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">Illuminate\Queue\SerializesModels</span>;</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(119, 0, 136)">use</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">Illuminate\Support\Facades\Log</span>;</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(119, 0, 136)">class</span> <span style="box-sizing: border-box;color: rgb(0, 0, 255)">SendEamilToUser</span> <span style="box-sizing: border-box;color: rgb(119, 0, 136)">implements</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">ShouldQueue</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">{</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">    <span style="box-sizing: border-box;color: rgb(119, 0, 136)">use</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">Dispatchable</span>, <span style="box-sizing: border-box;color: rgb(0, 0, 0)">InteractsWithQueue</span>, <span style="box-sizing: border-box;color: rgb(0, 0, 0)">Queueable</span>, <span style="box-sizing: border-box;color: rgb(0, 0, 0)">SerializesModels</span>;</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">    <span style="box-sizing: border-box;color: rgb(119, 0, 136)">public</span> <span style="box-sizing: border-box;color: rgb(0, 85, 170)">$user</span> <span style="box-sizing: border-box;color: rgb(152, 26, 26)">=</span> <span style="box-sizing: border-box;color: rgb(34, 17, 153)">null</span>;</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">    <span style="box-sizing: border-box;color: rgb(119, 0, 136)">public</span> <span style="box-sizing: border-box;color: rgb(119, 0, 136)">function</span> <span style="box-sizing: border-box;color: rgb(0, 0, 255)">__construct</span>(<span style="box-sizing: border-box;color: rgb(0, 0, 0)">User</span> <span style="box-sizing: border-box;color: rgb(0, 85, 170)">$user</span>)</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">    {</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">        <span style="box-sizing: border-box;color: rgb(0, 85, 170)">$this</span><span style="box-sizing: border-box;color: rgb(152, 26, 26)">-></span><span style="box-sizing: border-box;color: rgb(0, 0, 0)">user</span> <span style="box-sizing: border-box;color: rgb(152, 26, 26)">=</span> <span style="box-sizing: border-box;color: rgb(0, 85, 170)">$user</span>;</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">    }</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">    <span style="box-sizing: border-box;color: rgb(119, 0, 136)">public</span> <span style="box-sizing: border-box;color: rgb(119, 0, 136)">function</span> <span style="box-sizing: border-box;color: rgb(0, 0, 255)">handle</span>()</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">    {</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">        <span style="box-sizing: border-box;color: rgb(170, 85, 0)">// 此处执行自定义任务</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">        <span style="box-sizing: border-box;color: rgb(0, 0, 0)">Log</span>::<span style="box-sizing: border-box;color: rgb(0, 0, 0)">info</span>(<span style="box-sizing: border-box;color: rgb(170, 17, 17)">'发送邮件给 【'</span> . <span style="box-sizing: border-box;color: rgb(0, 85, 170)">$this</span><span style="box-sizing: border-box;color: rgb(152, 26, 26)">-></span><span style="box-sizing: border-box;color: rgb(0, 0, 0)">user</span><span style="box-sizing: border-box;color: rgb(152, 26, 26)">-></span><span style="box-sizing: border-box;color: rgb(0, 0, 0)">name</span> . <span style="box-sizing: border-box;color: rgb(170, 17, 17)">'】 用户成功'</span> );</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">    }</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">}</span>

第四步:派发任务给队列

1)定义路由

<span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(170, 85, 0)">// web.php</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(0, 0, 0)">Route</span>::<span style="box-sizing: border-box;color: rgb(0, 0, 0)">get</span>(<span style="box-sizing: border-box;color: rgb(170, 17, 17)">'queue'</span>, <span style="box-sizing: border-box;color: rgb(170, 17, 17)">'UserController@queue'</span>);</span>

2)添加queue方法并编写任务代码

<span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(170, 85, 0)">// UserController.php</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(119, 0, 136)">use</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">App\Jobs\SendEamilToUser</span>;</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(119, 0, 136)">public</span> <span style="box-sizing: border-box;color: rgb(119, 0, 136)">function</span> <span style="box-sizing: border-box;color: rgb(0, 0, 255)">queue</span>()</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">{</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">    <span style="box-sizing: border-box;color: rgb(0, 85, 170)">$users</span> <span style="box-sizing: border-box;color: rgb(152, 26, 26)">=</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">\App\Models\User</span>::<span style="box-sizing: border-box;color: rgb(0, 0, 0)">all</span>();</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">    <span style="box-sizing: border-box;color: rgb(119, 0, 136)">foreach</span> (<span style="box-sizing: border-box;color: rgb(0, 85, 170)">$users</span> <span style="box-sizing: border-box;color: rgb(119, 0, 136)">as</span> <span style="box-sizing: border-box;color: rgb(0, 85, 170)">$user</span>) {</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">        <span style="box-sizing: border-box;color: rgb(170, 85, 0)">// 为每个用户发送消息的任务</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">        <span style="box-sizing: border-box;color: rgb(170, 85, 0)">// 方式一</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">        <span style="box-sizing: border-box;color: rgb(170, 85, 0)">//dispatch(new SendEamilToUser($user));</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">    <span style="box-sizing: border-box;color: rgb(170, 85, 0)">// 方式二</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">        <span style="box-sizing: border-box;color: rgb(0, 0, 0)">SendEamilToUser</span>::<span style="box-sizing: border-box;color: rgb(0, 0, 0)">dispatch</span>(<span style="box-sizing: border-box;color: rgb(0, 85, 170)">$user</span>);</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">    }</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">    <span style="box-sizing: border-box;color: rgb(119, 0, 136)">return</span> <span style="box-sizing: border-box;color: rgb(170, 17, 17)">'派发队列任务成功'</span>;</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">}</span>

打开jobs数据表就会看到相关的任务信息了。

3)访问路由添加队列任务

<span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(170, 85, 0)">// 添加队列任务完成后,通过redis客户端进行查看。</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(17, 102, 68)">127.0</span>.<span style="box-sizing: border-box;color: rgb(17, 102, 68)">0.1</span>:<span style="box-sizing: border-box;color: rgb(17, 102, 68)">6379</span><span style="box-sizing: border-box;color: rgb(152, 26, 26)">></span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">keys</span> <span style="box-sizing: border-box;color: rgb(152, 26, 26)">*</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(17, 102, 68)">1</span>) <span style="box-sizing: border-box;color: rgb(170, 17, 17)">"laravel_database_queues:default:notify"</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(17, 102, 68)">2</span>) <span style="box-sizing: border-box;color: rgb(170, 17, 17)">"laravel_database_queues:default"</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(17, 102, 68)">127.0</span>.<span style="box-sizing: border-box;color: rgb(17, 102, 68)">0.1</span>:<span style="box-sizing: border-box;color: rgb(17, 102, 68)">6379</span><span style="box-sizing: border-box;color: rgb(152, 26, 26)">></span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">type</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">laravel_database_queues</span>:<span style="box-sizing: border-box;color: rgb(119, 0, 136)">default</span>:<span style="box-sizing: border-box;color: rgb(0, 0, 0)">notify</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(119, 0, 136)">list</span></span>

第五步:执行队列任务

<span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(170, 85, 0)">// 执行所有任务</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(0, 0, 0)">php</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">artisan</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">queue</span>:<span style="box-sizing: border-box;color: rgb(0, 0, 0)">work</span></span>

第六步:查询日志文件

<span style="box-sizing: border-box;padding-right: 0.1px">[<span style="box-sizing: border-box;color: rgb(17, 102, 68)">2021</span><span style="box-sizing: border-box;color: rgb(152, 26, 26)">-</span><span style="box-sizing: border-box;color: rgb(17, 102, 68)">07</span><span style="box-sizing: border-box;color: rgb(152, 26, 26)">-</span><span style="box-sizing: border-box;color: rgb(17, 102, 68)">09</span> <span style="box-sizing: border-box;color: rgb(17, 102, 68)">13</span>:<span style="box-sizing: border-box;color: rgb(17, 102, 68)">35</span>:<span style="box-sizing: border-box;color: rgb(17, 102, 68)">43</span>] <span style="box-sizing: border-box;color: rgb(0, 0, 0)">local</span>.<span style="box-sizing: border-box;color: rgb(0, 0, 0)">INFO</span>: <span style="box-sizing: border-box;color: rgb(0, 0, 0)">发送邮件给</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">【Dell</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">Terry】</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">用户成功</span>  </span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">[<span style="box-sizing: border-box;color: rgb(17, 102, 68)">2021</span><span style="box-sizing: border-box;color: rgb(152, 26, 26)">-</span><span style="box-sizing: border-box;color: rgb(17, 102, 68)">07</span><span style="box-sizing: border-box;color: rgb(152, 26, 26)">-</span><span style="box-sizing: border-box;color: rgb(17, 102, 68)">09</span> <span style="box-sizing: border-box;color: rgb(17, 102, 68)">13</span>:<span style="box-sizing: border-box;color: rgb(17, 102, 68)">35</span>:<span style="box-sizing: border-box;color: rgb(17, 102, 68)">43</span>] <span style="box-sizing: border-box;color: rgb(0, 0, 0)">local</span>.<span style="box-sizing: border-box;color: rgb(0, 0, 0)">INFO</span>: <span style="box-sizing: border-box;color: rgb(0, 0, 0)">发送邮件给</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">【Thomas</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">Bruen】</span> <span style="box-sizing: border-box;color: rgb(0, 0, 0)">用户成功</span>  </span>

如此,任务完成。

有没有注意到一个问题,要查看队列任务很不方便,与数据库相比,可观性太差了。好在,Laravel官方提供了Horizon扩展包解决了此问题。

可视化的Horizon队列系统解决方案

使用Horizon

第一步:安装Horizon

composer require laravel/horizon

报错: Install or enable PHP's pcntl extension.的解决方法

由于是在windows中,可能会报相关扩展的错误,错误如下:

- laravel/horizon[v5.7.0, ..., 5.x-dev] require ext-pcntl * -> it is missing from your system. Install or enable PHP's pcntl extension.
    - Root composer.json requires laravel/horizon ^5.7 -> satisfiable by laravel/horizon[v5.7.0, ..., 5.x-dev].

解决方法如下:

1)打开composer.json文件,添加如下配置

"config": {
    "optimize-autoloader": true,
    "preferred-install": "dist",
    "sort-packages": true,
    "platform": {
        "ext-pcntl": "7.2",
        "ext-posix": "7.2"
    }
},

2)安装

composer install

3)重新安装Horizon

第二步:发布资源并生成配置配置文件

php artisan horizon:install

config目录下生成horizon.php配置文件

第三步:访问后台

可以通过horizon路由对队列后台进行访问。

可以看到状态是Inactive未启动的状态,下面开始启动

第四步:运行Horizon

php artisan horizon

使用 php artisan horizon 报错:Call to undefined function Laravel\Horizon\Console\pcntl_async_signals()

很遗憾,pcntl扩展安装失败,虽然第一步的报错解决,显示也是安装成功,但是确实没有安装上。windows对此支持很是不友好,第四步无法执行成功。

windows下我没有找到解决方法,因此使用终端进行监控。

// 终端监控
php artisan queue:listen

到此使用horizon完毕

Horizon其他命令

暂停horizon

php artisan horizon:pause

继续horizon

php artisan horizon:continue

查看horizon状态

php artisan horizon:status

优雅的终止horizon

php artisan horizon:terminate

该命令会在所有当前正在执行的任务执行完成后退出horizon.

关于horizon还有一些其他的使用,请参考官方访访文档。

消息队列篇--完。

我是温新

每天进步一点点,就一点点

请登录后再评论