PHP+redis+SIGALRM信号实现队列可靠消费和消费超时控制

39 篇文章 2 订阅
<?php

namespace App\Console\Commands;

use App\Services\Topics;
use Illuminate\Console\Command;
use PhpSpec\Exception\Exception;
use Symfony\Component\Console\Input\InputOption;

/**
 * @brief       content
 * @author      weihaoyu
 * @createdAt   date
 * @updatedAt   date
 * @version     1.0
 */

class RedisQueueConsumer extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $name = 'why:redis_queue_consumer';
    protected $logName = 'redis_queue_consumer.log';

    private $sigalrm = 5;
    private $nowId;

    private $redis;

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '每天处理更新每个专题的问题补全,并生成静态html';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
        $this->redis = new \Redis();
        $this->redis->connect(env('REDIS_LIMIT_HOST'), env('REDIS_LIMIT_PORT'));
        $this->redis->auth(env('REDIS_LIMIT_PASSWORD'));
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        try{

            $queue = $this->option('queue');
            if(empty($queue)){
                $this->writeLog('no queue name');
                die;
            }
            $this->nowId = $id;
            $sigalrm = $this->option('sigalrm');
            if(!empty($sigalrm)){
                $this->sigalrm = $sigalrm;
            }

            $this->listenForSignals();

            while (true){
                $this->registerTimeoutHandler();
                $id = $this->redis->rpoplpush($queue, $queue . '_fail');
                if(empty($id)){
                    $this->writeLog('queue empty, exit');
                    exit;
                }

                $length = Topics::createHtmlFile((int)$id, base_path() . '/public/topics/');
                if($length > 0){
                    $this->redis->rpop($queue.'_fail');
                    $this->writeLog($this->nowId . '-write ' .$length. ' success');
                }else{
                    $this->writeLog($this->nowId . '-write ' .$length. ' fail');
                }
            }


        }catch (Exception $e){
            echo $e->getCode() . "\n";
            echo $e->getMessage() . "\n";
        }

    }


    protected function registerTimeoutHandler()
    {
        if ($this->supportsAsyncSignals()) {
            pcntl_signal(SIGALRM, function () {
                $msg = $this->nowId . '-timeout';
                $this->writeLog($msg);
            });
            pcntl_alarm($this->sigalrm);
        }
    }

    protected function writeLog($msg)
    {
        $str = date('Y-m-d H:i:s', time()) . ':' . $msg . "\n";
        file_put_contents(storage_path() . '/logs/' . $this->logName, $str, FILE_APPEND);
    }

    protected function listenForSignals()
    {
        if ($this->supportsAsyncSignals()) {
            pcntl_async_signals(true);
        }
    }

    protected function supportsAsyncSignals()
    {
        return version_compare(PHP_VERSION, '7.1.0') >= 0 && extension_loaded('pcntl');
    }

    protected function getOptions()
    {
        return array(
            array('queue', null, InputOption::VALUE_REQUIRED, 'queue name', null),
            array('sigalrm', null, InputOption::VALUE_REQUIRED, 'sigalrm time', null),
        );
    }

    public function __destruct()
    {
        $this->redis->close();
    }

}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AirGo.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值