From dd8fdee45fbd6e0c623a197122deaf35276744f8 Mon Sep 17 00:00:00 2001 From: Beno!t POLASZEK Date: Fri, 15 Mar 2024 15:35:39 +0100 Subject: [PATCH 1/4] fix: detect redis outages --- src/Hub/Transport/Redis/RedisTransport.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Hub/Transport/Redis/RedisTransport.php b/src/Hub/Transport/Redis/RedisTransport.php index a9cb864..1bc421f 100644 --- a/src/Hub/Transport/Redis/RedisTransport.php +++ b/src/Hub/Transport/Redis/RedisTransport.php @@ -13,6 +13,7 @@ use Generator; use React\EventLoop\Loop; use React\Promise\PromiseInterface; +use RuntimeException; use Symfony\Component\OptionsResolver\OptionsResolver; use function Freddie\maybeTimeout; @@ -50,6 +51,7 @@ public function __construct( if ($this->options['pingInterval']) { Loop::addPeriodicTimer($this->options['pingInterval'], fn () => $this->ping()); } + $this->subscriber->on('unsubscribe', fn () => Hub::die(new RuntimeException('Redis connection lost'))); } /** From 999511ad046176e37497dbefa59c2b030c9fa0c0 Mon Sep 17 00:00:00 2001 From: Beno!t POLASZEK Date: Fri, 15 Mar 2024 15:44:20 +0100 Subject: [PATCH 2/4] feat: immediately ping connection before subscribing --- src/Hub/Transport/Redis/RedisTransport.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Hub/Transport/Redis/RedisTransport.php b/src/Hub/Transport/Redis/RedisTransport.php index 1bc421f..45624cb 100644 --- a/src/Hub/Transport/Redis/RedisTransport.php +++ b/src/Hub/Transport/Redis/RedisTransport.php @@ -49,6 +49,7 @@ public function __construct( ]); $this->options = $resolver->resolve($options); if ($this->options['pingInterval']) { + $this->ping(); Loop::addPeriodicTimer($this->options['pingInterval'], fn () => $this->ping()); } $this->subscriber->on('unsubscribe', fn () => Hub::die(new RuntimeException('Redis connection lost'))); From f3d2dfde74f003388f335567d8be0e38c086ea48 Mon Sep 17 00:00:00 2001 From: Beno!t POLASZEK Date: Fri, 15 Mar 2024 16:09:19 +0100 Subject: [PATCH 3/4] tests(RedisTransportFactoryTest): set pingInterval to 0 so that `RedisTransport` doesn't connect to Redis within the unit test --- .../Redis/RedisTransportFactoryTest.php | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/tests/Unit/Hub/Transport/Redis/RedisTransportFactoryTest.php b/tests/Unit/Hub/Transport/Redis/RedisTransportFactoryTest.php index 8ca3a65..718567e 100644 --- a/tests/Unit/Hub/Transport/Redis/RedisTransportFactoryTest.php +++ b/tests/Unit/Hub/Transport/Redis/RedisTransportFactoryTest.php @@ -13,7 +13,7 @@ $factory = new RedisTransportFactory(); expect($factory->supports($dsn))->toBe($expected); })->with(function () { - yield ['redis://localhost', true]; + yield ['redis://localhost?pingInterval=0.0', true]; yield ['rediss://some.secure.place.com', true]; yield ['notredis://shrug', false]; }); @@ -23,21 +23,22 @@ expect($factory->create($dsn))->toEqual($expected); })->with(function () { $redisFactory = new Factory(); - yield ['redis://localhost?foo=bar', new RedisTransport( - $redisFactory->createLazyClient('redis://localhost?foo=bar'), - $redisFactory->createLazyClient('redis://localhost?foo=bar'), + yield ['redis://localhost?foo=bar&pingInterval=0.0', new RedisTransport( + $redisFactory->createLazyClient('redis://localhost?foo=bar&pingInterval=0.0'), + $redisFactory->createLazyClient('redis://localhost?foo=bar&pingInterval=0.0'), + options: ['pingInterval' => 0.0], )]; - yield ['redis://localhost?size=1000&trimInterval=2.5', new RedisTransport( - $redisFactory->createLazyClient('redis://localhost?size=1000&trimInterval=2.5'), - $redisFactory->createLazyClient('redis://localhost?size=1000&trimInterval=2.5'), - options: ['size' => 1000, 'trimInterval' => 2.5], + yield ['redis://localhost?size=1000&trimInterval=2.5&pingInterval=0.0', new RedisTransport( + $redisFactory->createLazyClient('redis://localhost?size=1000&trimInterval=2.5&pingInterval=0.0'), + $redisFactory->createLazyClient('redis://localhost?size=1000&trimInterval=2.5&pingInterval=0.0'), + options: ['size' => 1000, 'trimInterval' => 2.5, 'pingInterval' => 0.0], )]; }); it('instantiates 2 different clients', function () { $factory = new RedisTransportFactory(); /** @var RedisTransport $transport */ - $transport = $factory->create('redis://localhost?size=1000'); + $transport = $factory->create('redis://localhost?size=1000&pingInterval=0.0'); expect($transport->redis)->toBeInstanceOf(Client::class); expect($transport->subscriber)->toBeInstanceOf(Client::class); expect($transport->redis)->not()->toBe($transport->subscriber); From c632f1a06d809b7b1976406db48fd784c8f98498 Mon Sep 17 00:00:00 2001 From: Beno!t POLASZEK Date: Fri, 15 Mar 2024 16:11:49 +0100 Subject: [PATCH 4/4] tests(RedisTransportTest): set pingInterval to 0 so that `RedisTransport` doesn't connect to Redis within the unit test --- tests/Unit/Hub/Transport/Redis/RedisTransportTest.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/Unit/Hub/Transport/Redis/RedisTransportTest.php b/tests/Unit/Hub/Transport/Redis/RedisTransportTest.php index d8975a8..42335d4 100644 --- a/tests/Unit/Hub/Transport/Redis/RedisTransportTest.php +++ b/tests/Unit/Hub/Transport/Redis/RedisTransportTest.php @@ -16,7 +16,8 @@ $eventEmitter = new EventEmitter(); $transport = new RedisTransport( new RedisClientStub($storage, $eventEmitter), - new RedisClientStub($storage, $eventEmitter) + new RedisClientStub($storage, $eventEmitter), + options: ['pingInterval' => 0.0], ); // Given @@ -40,7 +41,7 @@ it('performs state reconciliation', function () { $client = new RedisClientStub(); - $transport = new RedisTransport($client, clone $client, options: ['size' => 3]); + $transport = new RedisTransport($client, clone $client, options: ['pingInterval' => 0.0, 'size' => 3]); // Given $updates = [ @@ -81,7 +82,11 @@ it('periodically trims the database', function () { $client = new RedisClientStub(); - $transport = new RedisTransport($client, clone $client, options: ['size' => 3, 'trimInterval' => 0.01]); + $transport = new RedisTransport($client, clone $client, options: [ + 'pingInterval' => 0.0, + 'size' => 3, + 'trimInterval' => 0.01 + ]); // Given $updates = [