Skip to content

Commit a9177da

Browse files
authored
Fixed redis connection has already been bound to another coroutine. (#2582)
* Added test cases. * Update * Update CHANGELOG-2.0.md
1 parent 174a431 commit a9177da

File tree

5 files changed

+76
-2
lines changed

5 files changed

+76
-2
lines changed

src/Redis.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ public function __call($name, $arguments)
5757
// Should storage the connection to coroutine context, then use defer() to release the connection.
5858
Context::set($this->getContextKey(), $connection);
5959
defer(function () use ($connection) {
60+
Context::set($this->getContextKey(), null);
6061
$connection->release();
6162
});
6263
} else {

tests/RedisProxyTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ private function getRedis($optinos = [])
113113
$container->shouldReceive('get')->once()->with(ConfigInterface::class)->andReturn(new Config([
114114
'redis' => [
115115
'default' => [
116-
'host' => 'localhost',
116+
'host' => '127.0.0.1',
117117
'auth' => null,
118118
'port' => 6379,
119119
'db' => 0,

tests/RedisTest.php

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use Hyperf\Redis\Redis;
2323
use Hyperf\Utils\ApplicationContext;
2424
use Hyperf\Utils\Context;
25+
use Hyperf\Utils\Coroutine;
2526
use HyperfTest\Redis\Stub\RedisPoolFailedStub;
2627
use HyperfTest\Redis\Stub\RedisPoolStub;
2728
use Mockery;
@@ -73,6 +74,52 @@ public function testRedisSelect()
7374
$this->assertSame('db:0 name:get argument:xxxx', $res[0]);
7475
}
7576

77+
public function testHasAlreadyBeenBoundToAnotherCoroutine()
78+
{
79+
$chan = new \Swoole\Coroutine\Channel(1);
80+
$redis = $this->getRedis();
81+
$ref = new \ReflectionClass($redis);
82+
$method = $ref->getMethod('getConnection');
83+
$method->setAccessible(true);
84+
85+
go(function () use ($chan, $redis, $method) {
86+
$id = null;
87+
defer(function () use ($redis, $chan, &$id, $method) {
88+
$chan->push(true);
89+
Coroutine::sleep(0.01);
90+
$hasContextConnection = Context::has('redis.connection.default');
91+
$this->assertFalse($hasContextConnection);
92+
$connection = $method->invoke($redis, [$hasContextConnection]);
93+
$this->assertNotEquals($connection->id, $id);
94+
$redis->getConnection();
95+
$chan->push(true);
96+
});
97+
98+
$redis->keys('*');
99+
100+
$hasContextConnection = Context::has('redis.connection.default');
101+
$this->assertFalse($hasContextConnection);
102+
103+
$redis->multi();
104+
$redis->set('id', uniqid());
105+
$redis->exec();
106+
107+
$hasContextConnection = Context::has('redis.connection.default');
108+
$this->assertTrue($hasContextConnection);
109+
110+
$connection = $method->invoke($redis, [$hasContextConnection]);
111+
$id = $connection->id;
112+
});
113+
114+
$chan->pop();
115+
$factory = $ref->getProperty('factory');
116+
$factory->setAccessible(true);
117+
$factory = $factory->getValue($redis);
118+
$pool = $factory->getPool('default');
119+
$pool->flushAll();
120+
$chan->pop();
121+
}
122+
76123
public function testRedisReuseAfterThrowable()
77124
{
78125
$container = $this->getContainer();
@@ -108,7 +155,7 @@ private function getContainer()
108155
$container->shouldReceive('get')->once()->with(ConfigInterface::class)->andReturn(new Config([
109156
'redis' => [
110157
'default' => [
111-
'host' => 'localhost',
158+
'host' => '127.0.0.1',
112159
'auth' => null,
113160
'port' => 6379,
114161
'db' => 0,

tests/Stub/RedisConnectionStub.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
*/
1212
namespace HyperfTest\Redis\Stub;
1313

14+
use Hyperf\Pool\Pool;
1415
use Hyperf\Redis\RedisConnection;
16+
use Psr\Container\ContainerInterface;
1517

1618
class RedisConnectionStub extends RedisConnection
1719
{
@@ -25,6 +27,14 @@ class RedisConnectionStub extends RedisConnection
2527

2628
public $timeout;
2729

30+
public $id;
31+
32+
public function __construct(ContainerInterface $container, Pool $pool, array $config)
33+
{
34+
parent::__construct($container, $pool, $config);
35+
$this->id = uniqid();
36+
}
37+
2838
public function __call($name, $arguments)
2939
{
3040
return sprintf('db:%d name:%s argument:%s', $this->db, $name, implode(',', $arguments));

tests/Stub/RedisPoolStub.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,26 @@
1212
namespace HyperfTest\Redis\Stub;
1313

1414
use Hyperf\Contract\ConnectionInterface;
15+
use Hyperf\Contract\StdoutLoggerInterface;
1516
use Hyperf\Redis\Pool\RedisPool;
1617

1718
class RedisPoolStub extends RedisPool
1819
{
20+
public function flushAll()
21+
{
22+
while ($conn = $this->channel->pop(0.001)) {
23+
try {
24+
$conn->close();
25+
} catch (\Throwable $exception) {
26+
if ($this->container->has(StdoutLoggerInterface::class) && $logger = $this->container->get(StdoutLoggerInterface::class)) {
27+
$logger->error((string) $exception);
28+
}
29+
} finally {
30+
--$this->currentConnections;
31+
}
32+
}
33+
}
34+
1935
protected function createConnection(): ConnectionInterface
2036
{
2137
return new RedisConnectionStub($this->container, $this, $this->config);

0 commit comments

Comments
 (0)