diff --git a/.github/wordlist.txt b/.github/wordlist.txt index 2130ad25..b199dd7e 100644 --- a/.github/wordlist.txt +++ b/.github/wordlist.txt @@ -4,6 +4,7 @@ CAS Customizable ElastiCache FPM +GC IANA Lua PSR diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b324765..3e6df707 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - Fixed PHP 8.4 deprecated call to `stream_context_set_option()` (#1545) - Fixed return type for `ZCOUNT` to be `int` (#1547) - fix(stream): Fixed throwing `CommunicationException` when stream is EOF (#1548) +- Removed automatic `conn_uid` parameter assignment (#1552) ## v3.0.1 (2025-05-16) ### Fixed diff --git a/README.md b/README.md index 8196b62e..276baa54 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,50 @@ it is still desired to have control of when the connection is opened or closed: achieved by invoking `$client->connect()` and `$client->disconnect()`. Please note that the effect of these methods on aggregate connections may differ depending on each specific implementation. +#### Persistent connections #### + +To increase a performance of your application you may set up a client to use persistent TCP connection, this way +client saves a time on socket creation and connection handshake. By default, connection is created on first-command +execution and will be automatically closed by GC before the process is being killed. +However, if your application is backed by PHP-FPM the processes are idle, and you may set up it to be persistent and +reusable across multiple script execution within the same process. + +To enable the persistent connection mode you should provide following configuration: + +```php +// Standalone +$client = new Predis\Client(['persistent' => true]); + +// Cluster +$client = new Predis\Client( + ['tcp://host:port', 'tcp://host:port', 'tcp://host:port'], + ['cluster' => 'redis', 'parameters' => ['persistent' => true]] +); +``` + +**Important** + +If you operate on multiple clients within the same application, and they communicate with the same resource, by default +they will share the same socket (that's the default behaviour of persistent sockets). So in this case you would need +to additionally provide a `conn_uid` identifier for each client, this way each client will create its own socket so +the connection context won't be shared across clients. This socket behaviour explained +[here](https://www.php.net/manual/en/function.stream-socket-client.php#105393) + +```php +// Standalone +$client1 = new Predis\Client(['persistent' => true, 'conn_uid' => 'id_1']); +$client2 = new Predis\Client(['persistent' => true, 'conn_uid' => 'id_2']); + +// Cluster +$client1 = new Predis\Client( + ['tcp://host:port', 'tcp://host:port', 'tcp://host:port'], + ['cluster' => 'redis', 'parameters' => ['persistent' => true, 'conn_uid' => 'id_1']] +); +$client2 = new Predis\Client( + ['tcp://host:port', 'tcp://host:port', 'tcp://host:port'], + ['cluster' => 'redis', 'parameters' => ['persistent' => true, 'conn_uid' => 'id_2']] +); +``` ### Client configuration ### diff --git a/src/Connection/StreamConnection.php b/src/Connection/StreamConnection.php index c90a981d..667dede7 100644 --- a/src/Connection/StreamConnection.php +++ b/src/Connection/StreamConnection.php @@ -59,8 +59,6 @@ class StreamConnection extends AbstractConnection public function __construct(ParametersInterface $parameters, ?StreamFactoryInterface $factory = null) { parent::__construct($parameters); - $this->parameters->conn_uid = spl_object_hash($this); - $this->streamFactory = $factory ?? new StreamFactory(); } diff --git a/tests/Predis/ClientTest.php b/tests/Predis/ClientTest.php index 592f5f8e..9ee51700 100644 --- a/tests/Predis/ClientTest.php +++ b/tests/Predis/ClientTest.php @@ -1325,21 +1325,40 @@ class ClientTest extends PredisTestCase /** * @group connected + * @requiresRedisVersion >= 5.0.0 */ public function testClientsCreateDifferentPersistentConnections(): void { - $client1 = new Client($this->getParameters(['database' => 14, 'persistent' => true])); - $client2 = new Client($this->getParameters(['database' => 15, 'persistent' => true])); + $client1 = new Client($this->getParameters(['database' => 14, 'persistent' => true, 'conn_uid' => 1])); + $client2 = new Client($this->getParameters(['database' => 15, 'persistent' => true, 'conn_uid' => 2])); $client1->set('foo', 'bar'); $client2->set('foo', 'baz'); $this->assertSame('bar', $client1->get('foo')); $this->assertSame('baz', $client2->get('foo')); + $this->assertNotSame($client1->client('ID'), $client2->client('ID')); $client1->disconnect(); $client2->disconnect(); } + /** + * @group connected + * @requiresRedisVersion >= 5.0.0 + */ + public function testClientsCreateSamePersistentConnections(): void + { + $client1 = new Client($this->getParameters(['persistent' => true])); + $client2 = new Client($this->getParameters(['persistent' => true])); + + $client1->set('foo', 'bar'); + $client2->set('foo', 'baz'); + + $this->assertSame('baz', $client2->get('foo')); + $this->assertSame($client1->client('ID'), $client2->client('ID')); + $client1->disconnect(); + } + /** * @group connected * @group cluster @@ -1349,11 +1368,11 @@ class ClientTest extends PredisTestCase { $client1 = new Client( $this->getDefaultParametersArray(), - ['cluster' => 'redis', 'parameters' => ['persistent' => true]] + ['cluster' => 'redis', 'parameters' => ['persistent' => true, 'conn_uid' => 1]] ); $client2 = new Client( $this->getDefaultParametersArray(), - ['cluster' => 'redis', 'parameters' => ['persistent' => true]] + ['cluster' => 'redis', 'parameters' => ['persistent' => true, 'conn_uid' => 2]] ); $client1->set('{shard1}foo', 'bar'); diff --git a/tests/Predis/Connection/ParametersTest.php b/tests/Predis/Connection/ParametersTest.php index cdd6ff26..78bc4ee6 100644 --- a/tests/Predis/Connection/ParametersTest.php +++ b/tests/Predis/Connection/ParametersTest.php @@ -403,6 +403,17 @@ class ParametersTest extends PredisTestCase $this->assertSame($expected, Parameters::parse($uri)); } + /** + * @group disconnected + */ + public function testSetParameters(): void + { + $parameters = new Parameters(); + $parameters->property = 'value'; + + $this->assertEquals('value', $parameters->property); + } + // ******************************************************************** // // ---- HELPER METHODS ------------------------------------------------ // // ******************************************************************** //