【已解决】Laravel完成定时Job任务(延时分发任务)【指定时间执行一次某自定义任务】

文章目录

  • 前言
  • 目标需求
  • 开发环境
    • Linux+Nginx+mysql+php7.3+Redis+Laravel 6.2.* + Supervisor管理器(用来做进程守护的工具)
  • 数据模型
    • 活动表(activity)
    • 用户表(userinfo)
  • 业务流程
  • 代码部分
  • 运行结果展示
  • 总结


前言

laravel 完成Job定时任务解决php在某一时间执行一次某个自定义任务。


目标需求

已知有多个活动且每个用户只能关注一个活动,活动表与用户表的关系为一对多【即“活动表”一条数据 关联 多条“用户表”数据】。现在要求活动开始前10分钟对关注该活动的用户进行消息推送提醒。

开发环境

Linux+Nginx+mysql+php7.3+Redis+Laravel 6.2.* + Supervisor管理器(用来做进程守护的工具)

注意:Laravel框架版本号不一定要和我的相同,该框架其他版本也有这个功能,更具自己的实际需要来。

数据模型

活动表(activity)

id(活动表id) name(活动名称) start_time (活动开始时间)
1 篮球活动比赛直播 2021-07-23 19:30:00
2 网球活动比赛直播 2021-07-25 09:30:00
3 游泳活动比赛直播 2021-07-28 15:00:00

用户表(userinfo)

id(用户表id) name(用户名) email(电子邮箱) activity_id(订阅活动表关联id) is_send(是否执行推送 0:否,1:是)
1 李琳 [email protected] 1 1
2 王涛 [email protected] 1 1
3 张英 [email protected] 2 0
4 孙鹏 [email protected] 3 0

真实数据库会设计成3张表,即 用户表、活动表、用户活动中间表。我这里为了简化演示流程省略中间表,仅设计2张表

业务流程

  1. 创建活动
  2. 程序更具活动 开始的时间减10分钟 创建Job定时推送任务(指定时间且仅执行一次的任务)
  3. 用户关注某个活动,建立与活动表的关联关系
  4. 系统到达某活动设置的执行推送时间,更具活动id获取关注该活动的用户,并执行推送服务。
  5. 执行推送服务后,改变用户表的推送状态标识。
  6. End;

代码部分

1.首先下载laravel6.2.*框架

composer create-project --prefer-dist laravel/laravel JobTaskDemo 6.2.*

2.进入项目内下载redis依赖扩展包 注意:要是你下的redis依赖装不上就查下你框架的版本或者php的版本与你当前装的redis拓展要求是否相符,不相符的去安装对应版本的redis拓展。

composer require predis/predis

3.创建数据模型 用户表、活动表(详情字段见上述表格)并完成表格迁移。

4.修改.env文件配置项,我们这里使用redis。(如果你的.env中有下述配置项则进行修改,没有则手动新增)

#这是redis配置项
REDIS_HOST=31.155.243.118 #你服务器的ip地址
REDIS_PASSWORD=aaaaa #你redis的密码,如果你没设置 就留空(留空的话=号后面别跟空格) 
REDIS_PORT=6379 #redis端口号
REDIS_DB=13 #redis数据库。redis默认有0-15个数据看。你用哪个就填哪个,我用的是13号数据库没有这个默认就是0号数据库(这个不改也行,个人喜好)

#添加如下配置
QUEUE_DRIVER=redis #默认链接队列名称 他的配置项在.\config\queue.php ->'default'
REDIS_QUEUE=queue_01 #redis队列 他的配置项在.\config\queue.php ->'connections'=>'redis'=>'queue'  这里的名字你自定义就好,这个值最终用在 任务将被发送到「testlist」队列  Job::dispatch()->onQueue('testlist');


#修改如下配置
#默认代码长这样QUEUE_CONNECTION=sync
QUEUE_CONNECTION=redis #默认队列连接名称 我们用的是 .\config\queue.php ->‘connections’=>'redis'配置项。所以这里写redis就好。

5.创建任务类 例如我想创建一个延时发送邮件的任务类(类名自定义,想叫啥随你喜欢):php artisan make:job DelaySendEmail

php artisan make:job 任务类名称(你自己定义)

【已解决】Laravel完成定时Job任务(延时分发任务)【指定时间执行一次某自定义任务】_第1张图片
6.分别创建控制器和控制器相对应的路由。格式:php artisan make:controller 你控制器的名称

 php artisan make:controller ActivityController

【已解决】Laravel完成定时Job任务(延时分发任务)【指定时间执行一次某自定义任务】_第2张图片

配置该控制器相应的路由
【已解决】Laravel完成定时Job任务(延时分发任务)【指定时间执行一次某自定义任务】_第3张图片

7.活动控制器代码



namespace App\Http\Controllers;

use App\Jobs\DelaySendEmail;
use App\Models\Activity;
use App\Models\Userinfo;
use Illuminate\Http\Request;

/**
 * 活动控制器
 * Class ActivityController
 * @package App\Http\Controllers
 */
class ActivityController extends Controller
{
     
    /**
     * 关注活动
     * @param Request $request
     */
    public function attention(Request $request){
     
        $user_id = (int)$request->user_id;//用户id
        $activity_id = (int)$request->activity_id;//活动id

        $activity = Activity::find($activity_id);//获取活动信息
        $time = time();//获取当前时间戳
        $start_time = strtotime($activity['start_time']);//计算活动开始的时间戳
        $time_difference = bcsub($start_time,$time,0);//计算时间差,得到多少秒后进行延时任务执行的秒数差
        
		//判断活动是否已经开始
        if($time_difference < 0) {
     
            return [
                'code'=>403,
                'mssage'=>'当前活动已结束',
                'success'=>0,//成功状态码 0:否,1:是
            ];
        }
        //更新当前用户与活动的关联关系
        $update = Userinfo::where('id',$user_id)->update(['activity_id'=>$activity_id]);
        //为啥要用->onQueue('queue_01') 执行队列名,因为如果你有多个项目都要部署job,不指定队列名可能导致A项目拿到了B项目的Job
        $this->dispatch((new DelaySendEmail($user_id, $time_difference))->onQueue('queue_01'));//方式A:
        //方式B:$this->dispatch((new DelaySendEmail($user_id, $time_difference))->onQueue('queue_01')->delay(now()->addSeconds($time_difference)));  代码解释:调用延迟任务进行邮件分发,并使用链式调用->addSeconds($time_difference)设计延迟执行的时间。
        $date = date('Y-m-d H:i:s');
        dump('等待执行',"延迟{
       $time_difference}秒后执行。","活动开始时间:{
       $activity['start_time']}","当前时间:{
       $date}");
    }
}

【已解决】Laravel完成定时Job任务(延时分发任务)【指定时间执行一次某自定义任务】_第4张图片

8.延迟发送邮件Job类



namespace App\Jobs;

use App\Models\Activity;
use App\Models\Userinfo;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;

/**
 * 延时发送邮件
 * Class DelaySendEmail
 * @package App\Jobs
 */
class DelaySendEmail implements ShouldQueue
{
     
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    private $userinfo;//用来保存用户信息

    /**
     * 构造函数
     * Create a new job instance.
     * DelaySendEmail constructor.
     * @param (int)$user_id 用户id
     * @param (int)$time_difference 执行延时任务的时间(秒)
     */
    public function __construct($user_id,$time_difference)
    {
     
        $userinfo = Userinfo::find($user_id);//获取用户信息
        $this->userinfo = $userinfo;//赋值用户信息
        $this->delay(now()->addSeconds($time_difference));//在 $time_difference 秒 后执行延时任务
        //$this->delay(now()->addSeconds($time_difference))写在外面的活动控制器中也可以,如:$this->dispatch((new DelaySendEmail($user_id, $time_difference))->delay(now()->addSeconds($time_difference)));
    }

    /**
     * 执行业务控制器
     * 用来执行延时任务的具体业务逻辑
     */
    public function handle()
    {
     
        //向指定用户发送邮件的代码业务逻辑
        //.....

        //判断邮件是否发送成功
        //.....假设已经发送成功

        //修改用户数据模型将状态改为1:已发送
        $update = Userinfo::where('id',$this->userinfo->id)->update(['is_send'=>1]);
    }
}

【已解决】Laravel完成定时Job任务(延时分发任务)【指定时间执行一次某自定义任务】_第5张图片

9.使用artisan 命令 执行队列监听 注意:这里的Dos窗口不能关闭,如果关闭或Ctrl+C键退出命令都会导致监听不在生效。

-执行监听:命令php artisan queue:work

  • 如何守护进程:所以你需要开启守护进程模式:在服务器上安装Supervisor管理器 配合命令一起使用实现守护进程
  • 如何重启队列:修改了队列的代码,但是不生效怎么办?
    如果改动了对列的代码需要执行下php artisan queue:restart使队列进行重启。

运行结果展示

1.设置活动开始时间
【已解决】Laravel完成定时Job任务(延时分发任务)【指定时间执行一次某自定义任务】_第6张图片
2.运行监听队列命令
【已解决】Laravel完成定时Job任务(延时分发任务)【指定时间执行一次某自定义任务】_第7张图片
3.用户请求延迟任务接口前的状态
【已解决】Laravel完成定时Job任务(延时分发任务)【指定时间执行一次某自定义任务】_第8张图片

4.用户请求接口,也就是说如果最后的用户表的更新时间为“2021-07-27 11:04:57”左右即表示我们运行成功。
【已解决】Laravel完成定时Job任务(延时分发任务)【指定时间执行一次某自定义任务】_第9张图片

5.延迟任务执行完毕后的结果(差了2秒,可能是代码运行或者服务器延迟所造成的)

【已解决】Laravel完成定时Job任务(延时分发任务)【指定时间执行一次某自定义任务】_第10张图片

总结

注意:
1.运行命令时,注意PHP的禁用函数是否开启。
2. env文件中 REDIS_QUEUE 一定要指定!不然当多个项目有Job需求时,你在一个项目中跑 php artisan queue:work 会拿到另外一个项目的 job,这样就会导致一些不必要的异常,因为在反序列化的过程中会找不到对应的类。
原因:.\config\queue.php 中’connections’配置的默认 queue 都是 default

【已解决】Laravel完成定时Job任务(延时分发任务)【指定时间执行一次某自定义任务】_第11张图片

如果这片文章帮助到了你,请帮我点个赞,您的支持是对我最大的鼓励!

你可能感兴趣的:(Laravel框架,laravel框架杂项,laravel,php)