From 18b1888b687ddd350beef77567e7a44b2e680a2b Mon Sep 17 00:00:00 2001 From: smarcet Date: Fri, 9 Oct 2026 21:33:51 -0300 Subject: [PATCH 1/2] feat(redis): opt-in persistent connections via REDIS_PERSISTENT Each php-fpm request opens a new TLS connection per redis connection it uses, and the TLS handshakes saturate the Valkey CPU during token bursts. With REDIS_PERSISTENT=true every redis connection keeps one persistent socket per worker, under its own persistent id. The connections share host:port, so a shared id would let one connection's SELECT switch the database of another within the same request. Defaults to off. Signed-off-by: smarcet --- config/database.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/config/database.php b/config/database.php index c43206a50..e8821a0a7 100644 --- a/config/database.php +++ b/config/database.php @@ -102,6 +102,12 @@ * @see https://github.com/predis/predis/wiki/Connection-Parameters */ 'cluster' => false, + /* + * REDIS_PERSISTENT=true keeps one TLS socket per connection in each php-fpm worker, + * so requests skip the TLS handshake. Every connection needs its own persistent id: + * they share host:port, and a shared socket would let one connection's SELECT + * switch the database of another within the same request. + */ 'default' => [ 'host' => env('REDIS_HOST'), @@ -110,6 +116,7 @@ 'password' => env('REDIS_PASSWORD'), 'timeout' => env('REDIS_TIMEOUT', 30.0), 'scheme' => env('REDIS_SCHEME', 'tcp'), + 'persistent' => env('REDIS_PERSISTENT', false) ? 'openstackid_default' : false, ], 'cache' => [ @@ -119,6 +126,7 @@ 'password' => env('REDIS_PASSWORD'), 'timeout' => env('REDIS_TIMEOUT', 30.0), 'scheme' => env('REDIS_SCHEME', 'tcp'), + 'persistent' => env('REDIS_PERSISTENT', false) ? 'openstackid_cache' : false, ], 'session' => [ @@ -128,6 +136,7 @@ 'password' => env('REDIS_PASSWORD'), 'timeout' => env('REDIS_TIMEOUT', 30.0), 'scheme' => env('REDIS_SCHEME', 'tcp'), + 'persistent' => env('REDIS_PERSISTENT', false) ? 'openstackid_session' : false, ], 'worker' => [ @@ -137,6 +146,7 @@ 'password' => env('REDIS_PASSWORD'), 'timeout' => env('REDIS_TIMEOUT', 30.0), 'scheme' => env('REDIS_SCHEME', 'tcp'), + 'persistent' => env('REDIS_PERSISTENT', false) ? 'openstackid_worker' : false, ], 'doctrine_cache' => [ 'host' => env('REDIS_HOST'), @@ -145,6 +155,7 @@ 'password' => env('REDIS_PASSWORD'), 'timeout' => env('REDIS_TIMEOUT', 30.0), 'scheme' => env('REDIS_SCHEME', 'tcp'), + 'persistent' => env('REDIS_PERSISTENT', false) ? 'openstackid_doctrine_cache' : false, ], ], 'allow_disabled_pk' => env('ALLOW_DISABLED_PK', false), From bf63f8779f8a33f8cf1faef910fa8ad25a8bef7a Mon Sep 17 00:00:00 2001 From: smarcet Date: Fri, 9 Oct 2026 21:47:13 -0300 Subject: [PATCH 2/2] fix(redis): set persistent_id so phpredis also keeps one socket per connection Laravel's PhpRedisConnector reads 'persistent' only as a flag and takes the socket id from 'persistent_id'. predis ignores the key. Signed-off-by: smarcet --- config/database.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/config/database.php b/config/database.php index e8821a0a7..ad1e8f8f4 100644 --- a/config/database.php +++ b/config/database.php @@ -106,7 +106,8 @@ * REDIS_PERSISTENT=true keeps one TLS socket per connection in each php-fpm worker, * so requests skip the TLS handshake. Every connection needs its own persistent id: * they share host:port, and a shared socket would let one connection's SELECT - * switch the database of another within the same request. + * switch the database of another within the same request. predis takes the id from + * 'persistent', phpredis from 'persistent_id'; both are set so either client is safe. */ 'default' => [ @@ -117,6 +118,7 @@ 'timeout' => env('REDIS_TIMEOUT', 30.0), 'scheme' => env('REDIS_SCHEME', 'tcp'), 'persistent' => env('REDIS_PERSISTENT', false) ? 'openstackid_default' : false, + 'persistent_id' => 'openstackid_default', ], 'cache' => [ @@ -127,6 +129,7 @@ 'timeout' => env('REDIS_TIMEOUT', 30.0), 'scheme' => env('REDIS_SCHEME', 'tcp'), 'persistent' => env('REDIS_PERSISTENT', false) ? 'openstackid_cache' : false, + 'persistent_id' => 'openstackid_cache', ], 'session' => [ @@ -137,6 +140,7 @@ 'timeout' => env('REDIS_TIMEOUT', 30.0), 'scheme' => env('REDIS_SCHEME', 'tcp'), 'persistent' => env('REDIS_PERSISTENT', false) ? 'openstackid_session' : false, + 'persistent_id' => 'openstackid_session', ], 'worker' => [ @@ -147,6 +151,7 @@ 'timeout' => env('REDIS_TIMEOUT', 30.0), 'scheme' => env('REDIS_SCHEME', 'tcp'), 'persistent' => env('REDIS_PERSISTENT', false) ? 'openstackid_worker' : false, + 'persistent_id' => 'openstackid_worker', ], 'doctrine_cache' => [ 'host' => env('REDIS_HOST'), @@ -156,6 +161,7 @@ 'timeout' => env('REDIS_TIMEOUT', 30.0), 'scheme' => env('REDIS_SCHEME', 'tcp'), 'persistent' => env('REDIS_PERSISTENT', false) ? 'openstackid_doctrine_cache' : false, + 'persistent_id' => 'openstackid_doctrine_cache', ], ], 'allow_disabled_pk' => env('ALLOW_DISABLED_PK', false),