diff --git a/app/Config/Cache.php b/app/Config/Cache.php index 1169c95ff7ee..1386bbfe1b85 100644 --- a/app/Config/Cache.php +++ b/app/Config/Cache.php @@ -112,14 +112,24 @@ class Cache extends BaseConfig * Your Redis server can be specified below, if you are using * the Redis or Predis drivers. * - * @var array{host?: string, password?: string|null, port?: int, timeout?: int, database?: int} + * @var array{ + * host?: string, + * password?: string|null, + * port?: int, + * timeout?: int, + * async?: bool, + * persistent?: bool, + * database?: int + * } */ public array $redis = [ - 'host' => '127.0.0.1', - 'password' => null, - 'port' => 6379, - 'timeout' => 0, - 'database' => 0, + 'host' => '127.0.0.1', + 'password' => null, + 'port' => 6379, + 'timeout' => 0, + 'async' => false, // this option only used by Predis + 'persistent' => false, + 'database' => 0, ]; /** diff --git a/system/Cache/Handlers/PredisHandler.php b/system/Cache/Handlers/PredisHandler.php index 250ea74a88e0..f7fd936abf59 100644 --- a/system/Cache/Handlers/PredisHandler.php +++ b/system/Cache/Handlers/PredisHandler.php @@ -36,15 +36,19 @@ class PredisHandler extends BaseHandler * host: string, * password: string|null, * port: int, + * async: bool, + * persistent: bool, * timeout: int * } */ protected $config = [ - 'scheme' => 'tcp', - 'host' => '127.0.0.1', - 'password' => null, - 'port' => 6379, - 'timeout' => 0, + 'scheme' => 'tcp', + 'host' => '127.0.0.1', + 'password' => null, + 'port' => 6379, + 'async' => false, + 'persistent' => false, + 'timeout' => 0, ]; /** diff --git a/system/Cache/Handlers/RedisHandler.php b/system/Cache/Handlers/RedisHandler.php index 3a13ee07f8e4..a79c757fe331 100644 --- a/system/Cache/Handlers/RedisHandler.php +++ b/system/Cache/Handlers/RedisHandler.php @@ -34,15 +34,17 @@ class RedisHandler extends BaseHandler * password: string|null, * port: int, * timeout: int, + * persistent: bool, * database: int, * } */ protected $config = [ - 'host' => '127.0.0.1', - 'password' => null, - 'port' => 6379, - 'timeout' => 0, - 'database' => 0, + 'host' => '127.0.0.1', + 'password' => null, + 'port' => 6379, + 'timeout' => 0, + 'persistent' => false, + 'database' => 0, ]; /** @@ -82,10 +84,11 @@ public function initialize() $this->redis = new Redis(); try { + $funcConnection = isset($config['persistent']) && $config['persistent'] ? 'pconnect' : 'connect'; + // Note:: If Redis is your primary cache choice, and it is "offline", every page load will end up been delayed by the timeout duration. // I feel like some sort of temporary flag should be set, to indicate that we think Redis is "offline", allowing us to bypass the timeout for a set period of time. - - if (! $this->redis->connect($config['host'], ($config['host'][0] === '/' ? 0 : $config['port']), $config['timeout'])) { + if (! $this->redis->{$funcConnection}($config['host'], ($config['host'][0] === '/' ? 0 : $config['port']), $config['timeout'])) { // Note:: I'm unsure if log_message() is necessary, however I'm not 100% comfortable removing it. log_message('error', 'Cache: Redis connection failed. Check your configuration.'); diff --git a/system/Session/Handlers/RedisHandler.php b/system/Session/Handlers/RedisHandler.php index eeb06043321b..7eb1924e95f0 100644 --- a/system/Session/Handlers/RedisHandler.php +++ b/system/Session/Handlers/RedisHandler.php @@ -142,17 +142,19 @@ protected function setSavePath(): void } } - $password = $query['auth'] ?? null; - $database = isset($query['database']) ? (int) $query['database'] : 0; - $timeout = isset($query['timeout']) ? (float) $query['timeout'] : 0.0; - $prefix = $query['prefix'] ?? null; + $persistent = isset($query['persistent']) ? (bool) $query['persistent'] : null; + $password = $query['auth'] ?? null; + $database = isset($query['database']) ? (int) $query['database'] : 0; + $timeout = isset($query['timeout']) ? (float) $query['timeout'] : 0.0; + $prefix = $query['prefix'] ?? null; $this->savePath = [ - 'host' => $host, - 'port' => $port, - 'password' => $password, - 'database' => $database, - 'timeout' => $timeout, + 'host' => $host, + 'port' => $port, + 'password' => $password, + 'database' => $database, + 'timeout' => $timeout, + 'persistent' => $persistent, ]; if ($prefix !== null) { @@ -176,8 +178,10 @@ public function open($path, $name): bool $redis = new Redis(); + $funcConnection = isset($this->savePath['persistent']) && $this->savePath['persistent'] ? 'pconnect' : 'connect'; + if ( - ! $redis->connect( + ! $redis->{$funcConnection}( $this->savePath['host'], $this->savePath['port'], $this->savePath['timeout'], diff --git a/tests/system/Session/Handlers/Database/RedisHandlerTest.php b/tests/system/Session/Handlers/Database/RedisHandlerTest.php index 19efb98cd50d..cc4254b9fb83 100644 --- a/tests/system/Session/Handlers/Database/RedisHandlerTest.php +++ b/tests/system/Session/Handlers/Database/RedisHandlerTest.php @@ -154,81 +154,111 @@ public static function provideSetSavePath(): iterable 'w/o protocol' => [ '127.0.0.1:6379', [ - 'host' => 'tcp://127.0.0.1', - 'port' => 6379, - 'password' => null, - 'database' => 0, - 'timeout' => 0.0, + 'host' => 'tcp://127.0.0.1', + 'port' => 6379, + 'password' => null, + 'database' => 0, + 'timeout' => 0.0, + 'persistent' => null, ], ], 'tls auth' => [ 'tls://127.0.0.1:6379?auth=password', [ - 'host' => 'tls://127.0.0.1', - 'port' => 6379, - 'password' => 'password', - 'database' => 0, - 'timeout' => 0.0, + 'host' => 'tls://127.0.0.1', + 'port' => 6379, + 'password' => 'password', + 'database' => 0, + 'timeout' => 0.0, + 'persistent' => null, ], ], 'tcp auth' => [ 'tcp://127.0.0.1:6379?auth=password', [ - 'host' => 'tcp://127.0.0.1', - 'port' => 6379, - 'password' => 'password', - 'database' => 0, - 'timeout' => 0.0, + 'host' => 'tcp://127.0.0.1', + 'port' => 6379, + 'password' => 'password', + 'database' => 0, + 'timeout' => 0.0, + 'persistent' => null, ], ], 'timeout float' => [ 'tcp://127.0.0.1:6379?timeout=2.5', [ - 'host' => 'tcp://127.0.0.1', - 'port' => 6379, - 'password' => null, - 'database' => 0, - 'timeout' => 2.5, + 'host' => 'tcp://127.0.0.1', + 'port' => 6379, + 'password' => null, + 'database' => 0, + 'timeout' => 2.5, + 'persistent' => null, ], ], 'timeout int' => [ 'tcp://127.0.0.1:6379?timeout=10', [ - 'host' => 'tcp://127.0.0.1', - 'port' => 6379, - 'password' => null, - 'database' => 0, - 'timeout' => 10.0, + 'host' => 'tcp://127.0.0.1', + 'port' => 6379, + 'password' => null, + 'database' => 0, + 'timeout' => 10.0, + 'persistent' => null, ], ], 'auth acl' => [ 'tcp://localhost:6379?auth[user]=redis-admin&auth[pass]=admin-password', [ - 'host' => 'tcp://localhost', - 'port' => 6379, - 'password' => ['user' => 'redis-admin', 'pass' => 'admin-password'], - 'database' => 0, - 'timeout' => 0.0, + 'host' => 'tcp://localhost', + 'port' => 6379, + 'password' => ['user' => 'redis-admin', 'pass' => 'admin-password'], + 'database' => 0, + 'timeout' => 0.0, + 'persistent' => null, ], ], 'unix domain socket' => [ 'unix:///tmp/redis.sock', [ - 'host' => '/tmp/redis.sock', - 'port' => 0, - 'password' => null, - 'database' => 0, - 'timeout' => 0.0, + 'host' => '/tmp/redis.sock', + 'port' => 0, + 'password' => null, + 'database' => 0, + 'timeout' => 0.0, + 'persistent' => null, ], ], 'unix domain socket w/o protocol' => [ '/tmp/redis.sock', [ - 'host' => '/tmp/redis.sock', - 'port' => 0, - 'password' => null, - 'database' => 0, - 'timeout' => 0.0, + 'host' => '/tmp/redis.sock', + 'port' => 0, + 'password' => null, + 'database' => 0, + 'timeout' => 0.0, + 'persistent' => null, + ], + ], + 'persistent connection' => [ + 'tcp://127.0.0.1:6379?timeout=10&persistent=1', + [ + 'host' => 'tcp://127.0.0.1', + 'port' => 6379, + 'password' => null, + 'database' => 0, + 'timeout' => 10.0, + 'persistent' => true, + ], + ], + 'no persistent connection with have parameter' => [ + 'tcp://127.0.0.1:6379?timeout=10&persistent=0', + [ + 'host' => 'tcp://127.0.0.1', + 'port' => 6379, + 'password' => null, + 'database' => 0, + 'timeout' => 10.0, + 'persistent' => false, ], ], ]; diff --git a/user_guide_src/source/changelogs/v4.7.0.rst b/user_guide_src/source/changelogs/v4.7.0.rst index 809d56b41291..8a14fb19b5bc 100644 --- a/user_guide_src/source/changelogs/v4.7.0.rst +++ b/user_guide_src/source/changelogs/v4.7.0.rst @@ -75,6 +75,8 @@ Libraries - **API Transformers:** This new feature provides a structured way to transform data for API responses. See :ref:`API Transformers ` for details. - **CLI:** Added ``SignalTrait`` to provide unified handling of operating system signals in CLI commands. +- **Cache:** Added ``async`` and ``persistent`` config item to predis handler. +- **Cache:** Added ``persistent`` config item to redis handler. - **CURLRequest:** Added ``shareConnection`` config item to change default share connection. - **CURLRequest:** Added ``dns_cache_timeout`` option to change default DNS cache timeout. - **CURLRequest:** Added ``fresh_connect`` options to enable/disable request fresh connection. @@ -83,6 +85,7 @@ Libraries - **Image:** The ``ImageMagickHandler`` has been rewritten to rely solely on the PHP ``imagick`` extension. - **Image:** Added ``ImageMagickHandler::clearMetadata()`` method to remove image metadata for privacy protection. - **ResponseTrait:** Added ``paginate``` method to simplify paginated API responses. See :ref:`ResponseTrait::paginate() ` for details. +- **Session:** Added ``persistent`` config item to redis handler. - **Time:** added methods ``Time::addCalendarMonths()`` and ``Time::subCalendarMonths()`` Commands diff --git a/user_guide_src/source/libraries/caching/014.php b/user_guide_src/source/libraries/caching/014.php index 6b0012696bf3..810448b4f6cc 100644 --- a/user_guide_src/source/libraries/caching/014.php +++ b/user_guide_src/source/libraries/caching/014.php @@ -9,11 +9,13 @@ class Cache extends BaseConfig // ... public $redis = [ - 'host' => '127.0.0.1', - 'password' => null, - 'port' => 6379, - 'timeout' => 0, - 'database' => 0, + 'host' => '127.0.0.1', + 'password' => null, + 'port' => 6379, + 'async' => false, + 'persistent' => false, + 'timeout' => 0, + 'database' => 0, ]; // ...