laravel中如何优雅的处理redis订阅超时的问题

默认情况下在laravel11中订阅redis频道会超时,代码如下:

<?php

namespace App\Console\Commands;

use App\Jobs\UpdateCallTaskJob;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Redis;

class SubscribeCdrCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'app:subscribe-cdr-command';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '订阅呼叫中心通话记录';

    /**
     * Execute the console command.
     */
    public function handle(): void
    {
        $this->info('开始订阅呼叫中心通话记录');
        Redis::subscribe(['cdr'], function ($message) {
            $data    = json_decode($message, true);
            $uuid    = $data['uuid'] ?? null;
            $task_id = $data['task_id'] ?? null;
            $this->info('已经订阅到消息');
            if ($uuid && $task_id) {
                $this->info('开始处理消息');
                UpdateCallTaskJob::dispatch($uuid, $task_id);
            }
        });
    }
}

设置了config/database.phpread_write_timeout为0也是会报错:

local.ERROR: read error on connection to 127.0.0.1:6379 {"exception":"[object] (RedisException(code: 0): read error on connection to 127.0.0.1:6379 at /www/wwwroot/callcenter.xxxxx.com/vendor/laravel/framework/src/Illuminate/Redis/Connections/PhpRedisConnection.php:459)
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
最佳答案

自问自答,设置Redis::OPT_READ_TIMEOUT为-1解决,完整代码如下:

<?php

namespace App\Console\Commands;

use Redis;
use RedisException;
use App\Jobs\UpdateCallTaskJob;
use Illuminate\Console\Command;

class SubscribeCdrCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'app:subscribe-cdr-command';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '订阅呼叫中心通话记录';

    /**
     * 执行命令
     * @return void
     * @throws RedisException
     */
    public function handle(): void
    {
        $this->info('开始订阅呼叫中心通话记录');
        $redis = app('redis');
        $redis->setOption(Redis::OPT_READ_TIMEOUT, -1);
        $redis->subscribe(['cdr'], function ($message) {
            $data    = json_decode($message, true);
            $uuid    = $data['uuid'] ?? null;
            $task_id = $data['task_id'] ?? null;
            $this->info('已经订阅到消息');
            if ($uuid && $task_id) {
                $this->info('开始处理消息');
                UpdateCallTaskJob::dispatch($uuid, $task_id);
            }
        });
    }
}
4个月前 评论
讨论数量: 5

try加重试

4个月前 评论
91it (楼主) 4个月前

看报错是 redis 长连接的问题,应该是 socket 超时导致的,调整超时加 supervisor 守护。问题是,redis 订阅机制不是可靠的,发布的那一刻,订阅者没接收到,再订阅,消息是没有的。

4个月前 评论
91it (楼主) 4个月前

自问自答,设置Redis::OPT_READ_TIMEOUT为-1解决,完整代码如下:

<?php

namespace App\Console\Commands;

use Redis;
use RedisException;
use App\Jobs\UpdateCallTaskJob;
use Illuminate\Console\Command;

class SubscribeCdrCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'app:subscribe-cdr-command';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '订阅呼叫中心通话记录';

    /**
     * 执行命令
     * @return void
     * @throws RedisException
     */
    public function handle(): void
    {
        $this->info('开始订阅呼叫中心通话记录');
        $redis = app('redis');
        $redis->setOption(Redis::OPT_READ_TIMEOUT, -1);
        $redis->subscribe(['cdr'], function ($message) {
            $data    = json_decode($message, true);
            $uuid    = $data['uuid'] ?? null;
            $task_id = $data['task_id'] ?? null;
            $this->info('已经订阅到消息');
            if ($uuid && $task_id) {
                $this->info('开始处理消息');
                UpdateCallTaskJob::dispatch($uuid, $task_id);
            }
        });
    }
}
4个月前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!