解决RedisException with message read error on connection

在使用phpredis扩展时,测试消息队列时用到了brpop和blpop这样的阻塞式命令。默认超过60秒以后会出现PHP异常

1
2
3
4
5
6
7
[root@localhost vagrant]# php queue.php 
PHP Fatal error: Uncaught exception 'RedisException' with message 'read error on connection' in /vagrant/queue.php:43
Stack trace:
#0 /vagrant/queue.php(43): Redis->brPop('emailQueue', '0')
#1 /vagrant/queue.php(54): EmailQueue->emailWorker()
#2 {main}
thrown in /vagrant/queue.php on line 43

以为是redis配置文件中设置了超时时间,查看了redis.conf后发现timeout默认已经设置为0

后来查看了一些资料发现由于phpredis底层默认使用的是php的socket方式,后来查看了php.ini发现default_socket_timeout = 60这一设置才明白。

不过不推荐直接修改php.ini文件,而是使用ini_set()函数来动态修改

ini_set('default_socket_timeout', -1); // 不超时

后来发现有人向phpredis作者提交了一个Pull requests见https://github.com/phpredis/phpredis/pull/260 . 里面给出了一个定义OPT_READ_TIMEOUT的选项 这里我设置成-1同样可以

1
2
3
4
5
$this->redis = new Redis();
$this->redis->pconnect('127.0.0.1', 6379);
$this->redis->setOption(Redis::OPT_READ_TIMEOUT, -1); //Note: You cannot setOption(Redis::OPT_READ_TIMEOUT, 0) to NOT time out. php_stream_set_option doesn't accept 0 for that purpose.
$this->redis->auth('xxxxxx');
$this->redis->select(15);

参考资料
https://github.com/phpredis/phpredis/issues/70
https://github.com/phpredis/phpredis/pull/260