mirror of
https://gitee.com/hyperf/hyperf.git
synced 2024-12-03 12:17:48 +08:00
Merge pull request #831 from limingxinleo/1.1-redis
Fixed redis not reconnect after redis server restarted.
This commit is contained in:
commit
bc166838f3
@ -5,19 +5,20 @@
|
||||
- [#812](https://github.com/hyperf/hyperf/pull/812) Added singleton crontab task support.
|
||||
- [#832](https://github.com/hyperf/hyperf/pull/832) Added `Hyperf\Utils\Codec\Json`.
|
||||
- [#833](https://github.com/hyperf/hyperf/pull/833) Added `Hyperf\Utils\Backoff`.
|
||||
- [#852](https://github.com/hyperf/hyperf/pull/852) Added method `clear` for Parallel to clear callbacks.
|
||||
- [#852](https://github.com/hyperf/hyperf/pull/852) Added a `clear()` method for `Hyperf\Utils\Parallel` to clear adde callbacks.
|
||||
|
||||
## Fixed
|
||||
|
||||
- [#831](https://github.com/hyperf/hyperf/pull/831) Fixed Redis client can not reconnect the server after the Redis server restarted.
|
||||
- [#835](https://github.com/hyperf/hyperf/pull/835) Fixed `Request::inputs` default value does not works.
|
||||
- [#841](https://github.com/hyperf/hyperf/pull/841) Fixed migration does not take effect under multiple data sources.
|
||||
- [#844](https://github.com/hyperf/hyperf/pull/844) Fixed the composer.json reader support root namespace.
|
||||
- [#844](https://github.com/hyperf/hyperf/pull/844) Fixed the reader of `composer.json` does not support the root namespace.
|
||||
- [#850](https://github.com/hyperf/hyperf/pull/850) Fixed logger group does not works when the name is same.
|
||||
|
||||
## Optimized
|
||||
|
||||
- [#832](https://github.com/hyperf/hyperf/pull/832) Optimized that response will throw a exception when json format failed.
|
||||
- [#840](https://github.com/hyperf/hyperf/pull/840) Use swoole timer function from namespace.
|
||||
- [#840](https://github.com/hyperf/hyperf/pull/840) Use `\Swoole\Timer::*` to instead of `swoole_timer_*` functions.
|
||||
|
||||
# v1.1.4 - 2019-10-31
|
||||
|
||||
|
@ -64,6 +64,7 @@ class ConnectionResolver implements ConnectionResolverInterface
|
||||
|
||||
if (! $connection instanceof ConnectionInterface) {
|
||||
$pool = $this->factory->getPool($name);
|
||||
// When Mysql connect failed, it will be catched by `Hyperf\Database\Connectors\ConnectionFactory`.
|
||||
$connection = $pool->get()->getConnection();
|
||||
Context::set($id, $connection);
|
||||
if (Coroutine::inCoroutine()) {
|
||||
|
@ -14,7 +14,6 @@ namespace Hyperf\Redis\Pool;
|
||||
|
||||
use Hyperf\Di\Container;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Swoole\Coroutine\Channel;
|
||||
|
||||
class PoolFactory
|
||||
{
|
||||
|
@ -39,6 +39,7 @@ class Redis
|
||||
$connection = $this->getConnection($hasContextConnection);
|
||||
|
||||
try {
|
||||
$connection = $connection->getConnection();
|
||||
// Execute the command with the arguments.
|
||||
$result = $connection->{$name}(...$arguments);
|
||||
} finally {
|
||||
@ -88,7 +89,7 @@ class Redis
|
||||
}
|
||||
if (! $connection instanceof RedisConnection) {
|
||||
$pool = $this->factory->getPool($this->poolName);
|
||||
$connection = $pool->get()->getConnection();
|
||||
return $pool->get();
|
||||
}
|
||||
return $connection;
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ declare(strict_types=1);
|
||||
namespace Hyperf\Redis;
|
||||
|
||||
use Hyperf\Contract\ConnectionInterface;
|
||||
use Hyperf\Contract\StdoutLoggerInterface;
|
||||
use Hyperf\Pool\Connection as BaseConnection;
|
||||
use Hyperf\Pool\Exception\ConnectionException;
|
||||
use Hyperf\Pool\Pool;
|
||||
@ -53,7 +54,13 @@ class RedisConnection extends BaseConnection implements ConnectionInterface
|
||||
|
||||
public function __call($name, $arguments)
|
||||
{
|
||||
return $this->connection->{$name}(...$arguments);
|
||||
try {
|
||||
$result = $this->connection->{$name}(...$arguments);
|
||||
} catch (\Throwable $exception) {
|
||||
$result = $this->retry($name, $arguments, $exception);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getActiveConnection()
|
||||
@ -125,4 +132,20 @@ class RedisConnection extends BaseConnection implements ConnectionInterface
|
||||
{
|
||||
$this->database = $database;
|
||||
}
|
||||
|
||||
protected function retry($name, $arguments, \Throwable $exception)
|
||||
{
|
||||
$logger = $this->container->get(StdoutLoggerInterface::class);
|
||||
$logger->warning(sprintf('Redis::__call failed, bacause ' . $exception->getMessage()));
|
||||
|
||||
try {
|
||||
$this->reconnect();
|
||||
$result = $this->connection->{$name}(...$arguments);
|
||||
} catch (\Throwable $exception) {
|
||||
$this->lastUseTime = 0.0;
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
@ -15,10 +15,15 @@ namespace HyperfTest\Redis;
|
||||
use Hyperf\Config\Config;
|
||||
use Hyperf\Contract\ConfigInterface;
|
||||
use Hyperf\Di\Container;
|
||||
use Hyperf\Pool\Channel;
|
||||
use Hyperf\Pool\PoolOption;
|
||||
use Hyperf\Redis\Frequency;
|
||||
use Hyperf\Redis\Pool\PoolFactory;
|
||||
use Hyperf\Redis\Pool\RedisPool;
|
||||
use Hyperf\Redis\Redis;
|
||||
use Hyperf\Utils\ApplicationContext;
|
||||
use Hyperf\Utils\Context;
|
||||
use HyperfTest\Redis\Stub\RedisPoolFailedStub;
|
||||
use HyperfTest\Redis\Stub\RedisPoolStub;
|
||||
use Mockery;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
@ -32,6 +37,7 @@ class RedisTest extends TestCase
|
||||
public function tearDown()
|
||||
{
|
||||
Mockery::close();
|
||||
Context::set('redis.connection.default', null);
|
||||
}
|
||||
|
||||
public function testRedisConnect()
|
||||
@ -68,9 +74,38 @@ class RedisTest extends TestCase
|
||||
$this->assertSame('db:0 name:get argument:xxxx', $res[0]);
|
||||
}
|
||||
|
||||
public function testRedisReuseAfterThrowable()
|
||||
{
|
||||
$container = $this->getContainer();
|
||||
$pool = new RedisPoolFailedStub($container, 'default');
|
||||
$container->shouldReceive('make')->once()->with(RedisPool::class, ['name' => 'default'])->andReturn($pool);
|
||||
$factory = new PoolFactory($container);
|
||||
$redis = new Redis($factory);
|
||||
try {
|
||||
$redis->set('xxxx', 'yyyy');
|
||||
} catch (\Throwable $exception) {
|
||||
$this->assertSame('Get connection failed.', $exception->getMessage());
|
||||
}
|
||||
|
||||
$this->assertSame(1, $pool->getConnectionsInChannel());
|
||||
$this->assertSame(1, $pool->getCurrentConnections());
|
||||
}
|
||||
|
||||
private function getRedis()
|
||||
{
|
||||
$container = $this->getContainer();
|
||||
$pool = new RedisPoolStub($container, 'default');
|
||||
$container->shouldReceive('make')->once()->with(RedisPool::class, ['name' => 'default'])->andReturn($pool);
|
||||
$factory = new PoolFactory($container);
|
||||
|
||||
return new Redis($factory);
|
||||
}
|
||||
|
||||
private function getContainer()
|
||||
{
|
||||
$container = Mockery::mock(Container::class);
|
||||
ApplicationContext::setContainer($container);
|
||||
|
||||
$container->shouldReceive('get')->once()->with(ConfigInterface::class)->andReturn(new Config([
|
||||
'redis' => [
|
||||
'default' => [
|
||||
@ -89,13 +124,13 @@ class RedisTest extends TestCase
|
||||
],
|
||||
],
|
||||
]));
|
||||
$pool = new RedisPoolStub($container, 'default');
|
||||
$container->shouldReceive('make')->once()->with(RedisPool::class, ['name' => 'default'])->andReturn($pool);
|
||||
|
||||
ApplicationContext::setContainer($container);
|
||||
|
||||
$factory = new PoolFactory($container);
|
||||
|
||||
return new Redis($factory);
|
||||
$container->shouldReceive('make')->with(Frequency::class, Mockery::any())->andReturn(new Frequency());
|
||||
$container->shouldReceive('make')->with(PoolOption::class, Mockery::any())->andReturnUsing(function ($class, $args) {
|
||||
return new PoolOption(...array_values($args));
|
||||
});
|
||||
$container->shouldReceive('make')->with(Channel::class, Mockery::any())->andReturnUsing(function ($class, $args) {
|
||||
return new Channel($args['size']);
|
||||
});
|
||||
return $container;
|
||||
}
|
||||
}
|
||||
|
21
src/redis/tests/Stub/RedisConnectionFailedStub.php
Normal file
21
src/redis/tests/Stub/RedisConnectionFailedStub.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://doc.hyperf.io
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
namespace HyperfTest\Redis\Stub;
|
||||
|
||||
class RedisConnectionFailedStub extends RedisConnectionStub
|
||||
{
|
||||
public function getConnection()
|
||||
{
|
||||
throw new \Exception('Get connection failed.');
|
||||
}
|
||||
}
|
@ -39,6 +39,8 @@ class RedisConnectionStub extends RedisConnection
|
||||
$this->db = $this->config['db'];
|
||||
$this->timeout = $this->config['timeout'];
|
||||
|
||||
$this->lastUseTime = microtime(true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
24
src/redis/tests/Stub/RedisPoolFailedStub.php
Normal file
24
src/redis/tests/Stub/RedisPoolFailedStub.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://doc.hyperf.io
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
namespace HyperfTest\Redis\Stub;
|
||||
|
||||
use Hyperf\Contract\ConnectionInterface;
|
||||
use Hyperf\Redis\Pool\RedisPool;
|
||||
|
||||
class RedisPoolFailedStub extends RedisPool
|
||||
{
|
||||
protected function createConnection(): ConnectionInterface
|
||||
{
|
||||
return new RedisConnectionFailedStub($this->container, $this, $this->config);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user