Skip to content

Commit b8582fa

Browse files
authored
Merge pull request #88 from clue-labs/lazy-close
Fix closing lazy connection from within rejection handler
2 parents cda663a + 75818b7 commit b8582fa

File tree

3 files changed

+29
-3
lines changed

3 files changed

+29
-3
lines changed

examples/subscribe.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
$client = $factory->createLazyClient('localhost');
1313
$client->subscribe($channel)->then(function () {
1414
echo 'Now subscribed to channel ' . PHP_EOL;
15-
}, function (Exception $e) {
15+
}, function (Exception $e) use ($client) {
16+
$client->close();
1617
echo 'Unable to subscribe: ' . $e->getMessage() . PHP_EOL;
1718
});
1819

src/LazyClient.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,10 @@ public function close()
166166
$this->promise->then(function (Client $client) {
167167
$client->close();
168168
});
169-
$this->promise->cancel();
170-
$this->promise = null;
169+
if ($this->promise !== null) {
170+
$this->promise->cancel();
171+
$this->promise = null;
172+
}
171173
}
172174

173175
if ($this->idleTimer !== null) {

tests/LazyClientTest.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,29 @@ public function testCloseAfterPingWillCancelIdleTimerWhenPingIsAlreadyResolved()
310310
$this->client->close();
311311
}
312312

313+
public function testCloseAfterPingRejectsWillEmitClose()
314+
{
315+
$deferred = new Deferred();
316+
$client = $this->getMockBuilder('Clue\React\Redis\StreamingClient')->disableOriginalConstructor()->setMethods(array('__call', 'close'))->getMock();
317+
$client->expects($this->once())->method('__call')->willReturn($deferred->promise());
318+
$client->expects($this->once())->method('close')->willReturnCallback(function () use ($client) {
319+
$client->emit('close');
320+
});
321+
322+
$this->factory->expects($this->once())->method('createClient')->willReturn(\React\Promise\resolve($client));
323+
324+
$timer = $this->getMockBuilder('React\EventLoop\TimerInterface')->getMock();
325+
$this->loop->expects($this->once())->method('addTimer')->willReturn($timer);
326+
$this->loop->expects($this->once())->method('cancelTimer')->with($timer);
327+
328+
$ref = $this->client;
329+
$ref->ping()->then(null, function () use ($ref, $client) {
330+
$ref->close();
331+
});
332+
$ref->on('close', $this->expectCallableOnce());
333+
$deferred->reject(new \RuntimeException());
334+
}
335+
313336
public function testEndWillCloseClientIfUnderlyingConnectionIsNotPending()
314337
{
315338
$this->client->on('close', $this->expectCallableOnce());

0 commit comments

Comments
 (0)