think-queue 消息队列 + redirs + Supervisor进程管理工具

gzy 2月前 172

think-queue 消息队列 + redirs + Supervisor进程管理工具

前言

此类文章已经很多。就不累赘了。 这篇文章hinkphp-queue就已经很详细了,本文介绍在实战中的运用。

一、Supervisor是什么?

Supervisor 是用Python开发的一套通用的进程管理程序,能将一个普通的命令行进程变为后台daemon,并监控进程状态,异常退出时能自动重启。也就是监控进程的状态。这篇文章Supervisor使用详解已经介绍很清楚了。

二、使用场景

1. 教育机构对结课学员课时,定时清零。

这个场景一般用的模式定时模式。已tp6为例。具体做法如下:

生产端 我们利用tp command创建自定义指令,查看创建自定义指令详解

配置和执行控制类

namespace app\command;

use app\common\business\queue\ThinkQueueStuCourseBusiness;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\Output;

class ClassEnding extends Command
{

    protected function configure()
    {
        // 指令配置
        $this->setName('classend')
            ->setDescription('结课处理');
    }

    protected function execute(Input $input, Output $output)
    {

        // 指令输出
        $output->writeln('============开始==============');

        $this->check();

        $output->writeln('============结束==============');
    }

    protected function check()
    {

        ThinkQueueStuCourseBusiness::getStuCourseList();
        return;

    }

}

业务逻辑类 hourClear方法就是把数据推送到队列中。

namespace app\common\business\queue;

use app\common\lib\queue\ThinkQueue;
use app\model\VendorMember;
use think\console\Output;
class ThinkQueueStuCourseBusiness
{
     /**
     * 获取列表
     */
    public static function getStuCourseList()
    {

        $list = (new VendorMember())->field('vendor_member_id,goods_status,is_del')->whereDay('student_expire_time')
                            ->where('is_del','=',0)
                            ->where('goods_status','<>',1)
                            ->select();

        foreach ($list as $key => $value) {

            self::hourClear($value);
            $date = date("Y-m-d H:i:s");
            (new Output)->writeln($date.' '."生产者:".$value['vendor_member_id']);

        }

        return true;
    }

    /**
     * 课时清零
     */
    public static function hourClear($jobData)
    {
        $jobData['method'] = 'fire';

        $jobHandlerClassName = 'app\common\queue\HourClear';

        $jobQueueName        = 'hourClear';

        $push = ThinkQueue::actionJob($jobData,$jobHandlerClassName,$jobQueueName);

        return $push;

    }

}

在console.php中添加配置

return [
    // 指令定义
    'commands' => [

        'CreateModels' => 'app\command\CreateModels',
        'classend'     => 'app\command\ClassEnding',
    ],
];

在queue.php中添加配置


return [
    'default'     => 'redis',
    'connections' => [
        'sync'     => [
            'type' => 'sync',
        ],

        'database' => [
            'type'       => 'database',
            'queue'      => 'default',
            'table'      => 'jobs',
            'connection' => null,
        ],

        'redis'    => [
            'type'       => 'redis',
            'queue'      => 'default',
            'host'       => '127.0.0.1',
            'port'       => 6379,
            'password'   => '',
            'select'     => 0,
            'timeout'    => 0,
            'persistent' => false,
        ],
    ],
    'failed'      => [
        'type'  => 'none',
        'table' => 'failed_jobs',
    ],
];
  run                 PHP Built-in Server for ThinkPHP
  version             show thinkphp framework version
 make
  make:command        Create a new command class
  make:controller     Create a new resource controller class
  make:event          Create a new event class
  make:listener       Create a new listener class
  make:middleware     Create a new middleware class
  make:model          Create a new model class
  make:service        Create a new Service class
  make:subscribe      Create a new subscribe class
  make:validate       Create a validate class
 optimize
  optimize:route      Build app route cache.
  optimize:schema     Build database schema cache.
 queue
  queue:failed        List all of the failed queue jobs
  queue:failed-table  Create a migration for the failed queue jobs database table
  queue:flush         Flush all of the failed queue jobs
  queue:forget        Delete a failed queue job
  queue:listen        Listen to a given queue
  queue:restart       Restart queue worker daemons after their current job

消费端 是处理队列中的数据。处理成功就删除队列中的数据。直到清零为止。

<?php

namespace app\common\queue;

use app\api\business\StudentCourseBusiness;
use think\facade\Log;
use think\queue\Job;
use think\console\Output;
class HourClear
{
    /**
     * fire方法是消息队列默认调用的方法
     * @param Job            $job      当前的任务对象
     * @param array|mixed    $data     发布任务时自定义的数据
     */
    public function fire(Job $job,$data)
    {

        // 有些消息在到达消费者时,可能已经不再需要执行了

        $isJobDone = $this->doHelloJob($data);

        if ($isJobDone) {

            $job->delete();
//
            Log::write(date('Y-m-d H:i:s').':'."<info>Hello Job has been done and deleted"."</info>",'info');

        } else {

            Log::write(date('Y-m-d H:i:s').':'."<info>失败"."</info>",'error');

            if ($job->attempts() > 3) {
                //通过这个方法可以检查这个任务已经重试了几次了
                Log::write(date('Y-m-d H:i:s').':'."<warn>Hello Job has been retried more than 3 times!"."</warn>",'info');

                $job->delete();

                // 也可以重新发布这个任务
                //print("<info>Hello Job will be availabe again after 2s."."</info>\n");
                //$job->release(2); //$delay为延迟时间,表示该任务延迟2秒后再执行
            }

        }

    }

    /**
     * 该方法用于接收任务执行失败的通知,你可以发送邮件给相应的负责人员
     * @param $jobData  string|array|...      //发布任务时传递的 jobData 数据
     */
    public function failed($jobData){

        print("Warning: Job failed after max retries. job data is");
    }

    /**
     * 有些消息在到达消费者时,可能已经不再需要执行了
     * @param array|mixed    $data     发布任务时自定义的数据
     * @return boolean                 任务执行的结果
     */
    private function checkDatabaseToSeeIfJobNeedToBeDone($data){
        return true;
    }

    /**
     * 根据消息中的数据进行实际的业务处理...
     */
    private function doHelloJob($data)
    {
        Log::write(date('Y-m-d H:i:s').':'.json_encode($data),'info');

        $vendor_member_id = isset($data['vendor_member_id']) ? $data['vendor_member_id'] : "";

        $save = (new StudentCourseBusiness())->edit(
            [
                'vendor_member_id' => $vendor_member_id,
                'goods_status' => 1,
                'student_remain_hours' => 0,
                'vendor_edit_time' => time()
            ]
        );

        if ($save !== true) {

            return false;
        }

        $date = date('Y-m-d H:i:s');

        (new Output)->writeln($date.' '."消费者:".$data['vendor_member_id']);

        return true;

    }

}

服务端 主要是使用Supervisor进程来管理进程。能将一个普通的命令行进程变为后台daemon,并监控进程状态,异常退出时能自动重启

提示:每天凌晨3执行,把数据推送到队列中。之后用Supervisor进行管理。

[root@localhost ~]# crontab -l
0 3 * * *  /usr/bin/php /var/www/tp/think classend 

[root@localhost supervisord.d]# pwd
/etc/supervisord.d
[root@localhost supervisord.d]# cat queue.ini
[program:queue]
directory = /var/www/tp
command = /usr/bin/php /var/www/tp/think queue:work --queue hourClear
process_name=%(program_name)s_%(process_num)02d
numprocs = 3           
autostart = true     
startsecs = 5        
autorestart = true  
startretries = 3    
user = root         
redirect_stderr = true 
stdout_logfile_maxbytes = 50MB 
stdout_logfile_backups = 20    
[root@localhost supervisord.d]# 

2. 订单下单之后超过30分钟用户未支付,需要取消订单

这个场景需要,只需要延迟进入入列就可以。超过 30分钟就执行。如果30分钟内付款。在消费类查询,是否付款。如果付款,直接把队列删除,否则就取消订单。相似逻辑处理。

  • 在生产者业务代码中
// 即时执行
$isPushed = Queue::push($jobHandlerClassName, $jobDataArr, $jobQueueName);

// 延迟 2 秒执行
$isPushed = Queue::later( 2, $jobHandlerClassName, $jobDataArr, $jobQueueName);

// 延迟到 2017-02-18 01:01:01 时刻执行
$time2wait = strtotime('2017-02-18 01:01:01') - strtotime('now');   
$isPushed = Queue::later($time2wait,$jobHandlerClassName, $jobDataArr, $jobQueueName);
  • :在消费者类中:
// 重发,即时执行
$job->release();

// 重发,延迟 2 秒执行
$job->release(2);

// 延迟到 2017-02-18 01:01:01 时刻执行
$time2wait = strtotime('2017-02-18 01:01:01') - strtotime('now');
$job->release($time2wait);

总结

希望这篇文章对大家有些帮助。本人经验有限,有描写不对的,或其他更好的方法。欢迎讨论。 think-queue 消息队列 + redirs + Supervisor进程管理工具

think-queue 手册

创建自定义指令详解

最新回复 (0)
    • 都市菜鸟网
      2
        立即登录 立即注册 
返回