Laravel 实现 队列 发送邮件功能

一. 什么是队列

在构建 Web 应用程序时,你可能需要执行一些任务,例如解析文件,发送邮件,大量的数据计算等等,这些任务在典型的 Web 请求期间需要很长时间才能执行

庆幸的是,Laravel 可以创建在后台运行的队列任务。 通过将时间密集型任务移至队列,你的应用程序可以以极快的速度响应 Web 请求,并为你的客户提供更好的用户体验。

说人话:laravel可以轻松创建,后台运行的队列,再将耗时的任务移到队列,减少用户在页面上的等待时间,提高用户体验。

二. 配置队列驱动

队列驱动 就是 以哪个方式来处理队列任务。

常见的驱动如下:

1.sync 驱动 (同步)

.env 文件 编辑

php 复制代码
QUEUE_CONNECTION=sync

特点是: 任务立即执行,不进入队列, 适合开发和测试环境,请求会阻塞直到任务完成

我一般是本地和测试使用,如果使用这个,那就跟队列没什么关系了,直接同步执行

2. database 驱动

php 复制代码
QUEUE_CONNECTION=database

数据库驱动时,肯定首先需要创建数据表的。用来存储队列服务的。如下

php 复制代码
php artisan queue:table
php artisan migrate

会创建两个表,存储任务数据

打开 config/queue.php 文件,配置一下

php 复制代码
'database' => [
    'driver' => 'database',
    'table' => 'jobs',
    'queue' => 'default',
    'retry_after' => 90,
],

特点是:使用的是数据库存储任务,不需要单独配置服务,有数据库即可,适合中小规模项目

3. redis 驱动 (推荐)

php 复制代码
QUEUE_CONNECTION=redis

打开 config/queue.php 文件,配置一下

php 复制代码
 'redis' => [
     'driver' => 'redis',
     'connection' => 'default',
     'queue' => env('REDIS_QUEUE', 'default'),
     'retry_after' => 90,
     'block_for' => null,
     'after_commit' => false,
 ],

注意

利用 redis 做为驱动的话,前提一定要配置好 redis

特点:高性能适合生产环境支持队列优先级

其他的驱动,暂时不做说明,大家可以自己去研究下。

三.创建队列任务

1. 生成任务类

php 复制代码
php artisan make:job ProjectJob

生成的文件位于 app/Jobs/ProjectJob.php

2.任务类开发逻辑

php 复制代码
<?php

namespace App\Jobs;

use App\Http\Services\ProjectService;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;

/**
 * 项目工程队列
 */
class ProjectJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public array $reqData;

    /**
     * 任务支持错误,可尝试的次数。
     *
     * @var int
     */
    public $tries = 5;
    
    /**
     * Create a new job instance.
     */
    public function __construct($data = [])
    {
        $this->reqData = $data;

        $this->onQueue('project-compute');
    }

    /**
     * Execute the job.
     */
    public function handle(): void
    {
        $data = $this->reqData;
		
		// 开始发送邮件功能,大量耗时的任务开始编码
		
        Log::info("===project-compute-Log===", [$data, $res]);
    }

}

3.唯一任务实现

有时,希望这个队列在任务时间点,只有一个任务的实例,只需要实现 ShouldBeUnique 即可。

php 复制代码
<?php

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Contracts\Queue\ShouldBeUnique;

class ProjectJob implements ShouldQueue, ShouldBeUnique
{

    public $Project;

    /**
     * 唯一锁将被释放的秒数
     *
     * @var int
     */
    public $uniqueFor = 20;

    /**
     * 任务的唯一 ID
     */
    public function uniqueId(): string
    {
        return $this->Project->id;
    }
}

如上:同一个 Project->id 在 20 秒内,都会被忽略,当 20 秒后,相同的id任务会再次分配到队列

四. 分发队列任务

分发,也就是怎么在控制器里面 去 将任务 丢到队列。

1.基本分发方式

php 复制代码
ProjectJob ::dispatch(['data':"123"]);

2.延迟分发,10分钟后

php 复制代码
ProjectJob ::dispatch(['data':"123"])->delay(now()->addMinutes(10));;

3.同步分发,立即执行

php 复制代码
ProjectJob ::dispatchSync(['data':"123"]);

4. 指定队列

php 复制代码
ProjectJob ::dispatch(['data':"123"])->onQueue('high');

五. 队列工作进程管理

1. 启动队列工作进程

shell 复制代码
php artisan queue:work

2. 常用选项

shell 复制代码
# 指定队列连接
php artisan queue:work --queue=high

php artisan queue:work --queue=high,default

--queue=high,default 是启动了一个工作进程,但该进程会按照优先级处理多个队列中的任务

3. 重启队列

在队列的代码修改了,那么就需要重启队列。

shell 复制代码
php artisan queue:restart

由于队列任务是长期存在的进程,如果不重新启动,他们不会注意到代码的更改。

可以通过发出 queue:restart 命令优雅地重新启动所有进程

queue:restart 说明:
  1. 不是真正的进程重启:

    • 不会终止或重新创建现有的队列工作进程

    • 不会改变进程ID(PID)或端口

    • 现有进程会继续完成当前正在处理的任务

  2. 优雅重启机制:

    • 在存储系统(缓存/数据库)中设置重启标记

    • 工作进程在完成当前任务后检查到标记,会自行退出

    • 进程管理器(如Supervisor)会自动重新启动新进程

注意

我的队列进程就是 用 Supervisor 托管的,所以在 queue:restart 后,Supervisor 会自动重启我的队列进程。

当前队列进程启动后,在控制器内,丢入任务到队列,队列就会排队处理任务了。

如下图所示,队列的处理日志。

六. 处理失败的任务

在任务处理失败时,队列会先尝试在运行几次,见 2.任务类开发逻辑tries 参数,超过此尝试次数后,它将被插入到 failed_jobs 数据库表中

shell 复制代码
php artisan queue:failed-table

php artisan migrate

可以使用 queue:failed-table 命令来创建迁移错误任务表

1.查看失败任务

shell 复制代码
php artisan queue:failed

如图:

2. 重试失败的任务

shell 复制代码
#重试单个任务id
php artisan queue:retry ce7bb17c-cdd8-41f0-a8ec-7b4fef4e5ece

# 重试多个任务id
php artisan queue:retry ce7bb17c-cdd8-41f0-a8ec-7b4fef4e5ece 91401d2c-0784-4f43-824c-34f94a33c24d

# 重试指定队列的所有失败任务
php artisan queue:retry --queue=name

#重试所有失败任务
php artisan queue:retry all

执行后

3.清理失败任务

shell 复制代码
#要删除指定的失败任务
php artisan queue:forget 91401d2c-0784-4f43-824c-34f94a33c24d

# 删除 failed_jobs 表中所有失败任务
php artisan queue:flush

如图

通过以上配置和使用方法,你可以充分利用Laravel队列系统来提高应用性能和用户体验。

在实际的使用中,会遇到各种问题,大家可以自行去拓展,里面有很多的参数设置和功能,我这边就不一一去说明,边用边学。

相关推荐
林深时见鹿7498 小时前
使用k8s k3s kuboard 部署 php hyperf 框架
php
长城20248 小时前
从词源和输出生成等角度详细解析PHP中常用文件操作类函数
php·文件·函数·文件操作函数
长城20249 小时前
PHP如何使用JpGraph生成3D饼形图?
开发语言·php·jpgraph·3d饼形图
熬夜苦读学习16 小时前
Reactor 反应堆模式
运维·服务器·网络·网络协议·http·智能路由器·php
小森林816 小时前
分享一次Guzzlehttp上传批量图片优化的经历
后端·php
THMAIL16 小时前
大模型0基础开发入门与实践:第11章 进阶:LangChain与外部工具调用
开发语言·langchain·php
分享点2 天前
Laravel 使用阿里云OSS S3 协议文件上传
阿里云·php·laravel
苏琢玉2 天前
订单号老是撞车?我写了个通用 PHP ID 生成器
php·composer
BingoGo2 天前
PHP 测试框架 Pest v4 正式发布 革命性的浏览器测试体验
后端·php
搬码临时工2 天前
通过自定义域名访问内网的web服务和tcp应用:内网ip到局域网外域名访问过程
服务器·tcp/ip·php