mirror of
https://gitee.com/hyperf/hyperf.git
synced 2024-12-04 04:37:46 +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.
|
- [#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`.
|
- [#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`.
|
- [#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
|
## 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.
|
- [#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.
|
- [#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.
|
- [#850](https://github.com/hyperf/hyperf/pull/850) Fixed logger group does not works when the name is same.
|
||||||
|
|
||||||
## Optimized
|
## Optimized
|
||||||
|
|
||||||
- [#832](https://github.com/hyperf/hyperf/pull/832) Optimized that response will throw a exception when json format failed.
|
- [#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
|
# v1.1.4 - 2019-10-31
|
||||||
|
|
||||||
|
@ -64,6 +64,7 @@ class ConnectionResolver implements ConnectionResolverInterface
|
|||||||
|
|
||||||
if (! $connection instanceof ConnectionInterface) {
|
if (! $connection instanceof ConnectionInterface) {
|
||||||
$pool = $this->factory->getPool($name);
|
$pool = $this->factory->getPool($name);
|
||||||
|
// When Mysql connect failed, it will be catched by `Hyperf\Database\Connectors\ConnectionFactory`.
|
||||||
$connection = $pool->get()->getConnection();
|
$connection = $pool->get()->getConnection();
|
||||||
Context::set($id, $connection);
|
Context::set($id, $connection);
|
||||||
if (Coroutine::inCoroutine()) {
|
if (Coroutine::inCoroutine()) {
|
||||||
|
@ -14,7 +14,6 @@ namespace Hyperf\Redis\Pool;
|
|||||||
|
|
||||||
use Hyperf\Di\Container;
|
use Hyperf\Di\Container;
|
||||||
use Psr\Container\ContainerInterface;
|
use Psr\Container\ContainerInterface;
|
||||||
use Swoole\Coroutine\Channel;
|
|
||||||
|
|
||||||
class PoolFactory
|
class PoolFactory
|
||||||
{
|
{
|
||||||
|
@ -39,6 +39,7 @@ class Redis
|
|||||||
$connection = $this->getConnection($hasContextConnection);
|
$connection = $this->getConnection($hasContextConnection);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
$connection = $connection->getConnection();
|
||||||
// Execute the command with the arguments.
|
// Execute the command with the arguments.
|
||||||
$result = $connection->{$name}(...$arguments);
|
$result = $connection->{$name}(...$arguments);
|
||||||
} finally {
|
} finally {
|
||||||
@ -88,7 +89,7 @@ class Redis
|
|||||||
}
|
}
|
||||||
if (! $connection instanceof RedisConnection) {
|
if (! $connection instanceof RedisConnection) {
|
||||||
$pool = $this->factory->getPool($this->poolName);
|
$pool = $this->factory->getPool($this->poolName);
|
||||||
$connection = $pool->get()->getConnection();
|
return $pool->get();
|
||||||
}
|
}
|
||||||
return $connection;
|
return $connection;
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ declare(strict_types=1);
|
|||||||
namespace Hyperf\Redis;
|
namespace Hyperf\Redis;
|
||||||
|
|
||||||
use Hyperf\Contract\ConnectionInterface;
|
use Hyperf\Contract\ConnectionInterface;
|
||||||
|
use Hyperf\Contract\StdoutLoggerInterface;
|
||||||
use Hyperf\Pool\Connection as BaseConnection;
|
use Hyperf\Pool\Connection as BaseConnection;
|
||||||
use Hyperf\Pool\Exception\ConnectionException;
|
use Hyperf\Pool\Exception\ConnectionException;
|
||||||
use Hyperf\Pool\Pool;
|
use Hyperf\Pool\Pool;
|
||||||
@ -53,7 +54,13 @@ class RedisConnection extends BaseConnection implements ConnectionInterface
|
|||||||
|
|
||||||
public function __call($name, $arguments)
|
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()
|
public function getActiveConnection()
|
||||||
@ -125,4 +132,20 @@ class RedisConnection extends BaseConnection implements ConnectionInterface
|
|||||||
{
|
{
|
||||||
$this->database = $database;
|
$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\Config\Config;
|
||||||
use Hyperf\Contract\ConfigInterface;
|
use Hyperf\Contract\ConfigInterface;
|
||||||
use Hyperf\Di\Container;
|
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\PoolFactory;
|
||||||
use Hyperf\Redis\Pool\RedisPool;
|
use Hyperf\Redis\Pool\RedisPool;
|
||||||
use Hyperf\Redis\Redis;
|
use Hyperf\Redis\Redis;
|
||||||
use Hyperf\Utils\ApplicationContext;
|
use Hyperf\Utils\ApplicationContext;
|
||||||
|
use Hyperf\Utils\Context;
|
||||||
|
use HyperfTest\Redis\Stub\RedisPoolFailedStub;
|
||||||
use HyperfTest\Redis\Stub\RedisPoolStub;
|
use HyperfTest\Redis\Stub\RedisPoolStub;
|
||||||
use Mockery;
|
use Mockery;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
@ -32,6 +37,7 @@ class RedisTest extends TestCase
|
|||||||
public function tearDown()
|
public function tearDown()
|
||||||
{
|
{
|
||||||
Mockery::close();
|
Mockery::close();
|
||||||
|
Context::set('redis.connection.default', null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRedisConnect()
|
public function testRedisConnect()
|
||||||
@ -68,9 +74,38 @@ class RedisTest extends TestCase
|
|||||||
$this->assertSame('db:0 name:get argument:xxxx', $res[0]);
|
$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()
|
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);
|
$container = Mockery::mock(Container::class);
|
||||||
|
ApplicationContext::setContainer($container);
|
||||||
|
|
||||||
$container->shouldReceive('get')->once()->with(ConfigInterface::class)->andReturn(new Config([
|
$container->shouldReceive('get')->once()->with(ConfigInterface::class)->andReturn(new Config([
|
||||||
'redis' => [
|
'redis' => [
|
||||||
'default' => [
|
'default' => [
|
||||||
@ -89,13 +124,13 @@ class RedisTest extends TestCase
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
]));
|
]));
|
||||||
$pool = new RedisPoolStub($container, 'default');
|
$container->shouldReceive('make')->with(Frequency::class, Mockery::any())->andReturn(new Frequency());
|
||||||
$container->shouldReceive('make')->once()->with(RedisPool::class, ['name' => 'default'])->andReturn($pool);
|
$container->shouldReceive('make')->with(PoolOption::class, Mockery::any())->andReturnUsing(function ($class, $args) {
|
||||||
|
return new PoolOption(...array_values($args));
|
||||||
ApplicationContext::setContainer($container);
|
});
|
||||||
|
$container->shouldReceive('make')->with(Channel::class, Mockery::any())->andReturnUsing(function ($class, $args) {
|
||||||
$factory = new PoolFactory($container);
|
return new Channel($args['size']);
|
||||||
|
});
|
||||||
return new Redis($factory);
|
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->db = $this->config['db'];
|
||||||
$this->timeout = $this->config['timeout'];
|
$this->timeout = $this->config['timeout'];
|
||||||
|
|
||||||
|
$this->lastUseTime = microtime(true);
|
||||||
|
|
||||||
return 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