From 3227bc695b4809caa86235a5677a21d18f37e0a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Till=20Kru=CC=88ss?= Date: Sat, 7 Oct 2023 09:29:56 -0700 Subject: [PATCH 1/3] wip --- README.md | 6 +++- includes/class-plugin.php | 16 ++------- includes/class-predis.php | 62 ++++++++++++++++++++++++++------- includes/cli/class-commands.php | 15 ++------ 4 files changed, 59 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 20594f70..6ddc1407 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # Redis Object Cache for WordPress +Update Banner: Fast load times; Less Database load; screenshots +Add: SpinupWP, BlueHost, LiquidWeb and other platforms that use it to the banner maybe also to the readme + A persistent object cache backend powered by Redis®¹. Supports [Predis](https://github.com/predis/predis/), [PhpRedis (PECL)](https://github.com/phpredis/phpredis), [Relay](https://relaycache.com), replication, sentinels, clustering and [WP-CLI](http://wp-cli.org/). [![Redis Object Cache screenshots](/.wordpress-org/collage-sm.jpg?raw=true)](/.wordpress-org/collage.png?raw=true) @@ -41,7 +44,8 @@ The Redis Object Cache plugin comes with vast set of configuration options. If y | `WP_REDIS_MAXTTL` | `0` | The maximum time-to-live of cache keys | | `WP_REDIS_CLIENT` | | The client used to communicate with Redis. Defaults to `phpredis` when installed, otherwise `predis`. Supports `phpredis`, `predis`, `relay` | | `WP_REDIS_TIMEOUT` | `1` | The connection timeout in seconds | -| `WP_REDIS_READ_TIMEOUT` | `1` | The timeout in seconds when reading/writing | +| `WP_REDIS_READ_TIMEOUT` | `1` | The timeout in seconds when reading/writing | +| `WP_REDIS_FLUSH_TIMEOUT` | `5` | The timeout in seconds when flushing | | `WP_REDIS_IGNORED_GROUPS` | `[]` | Groups that should not be cached between requests in Redis |
diff --git a/includes/class-plugin.php b/includes/class-plugin.php index 047d980c..b3651323 100644 --- a/includes/class-plugin.php +++ b/includes/class-plugin.php @@ -946,13 +946,7 @@ public function do_admin_actions() { ); if ( $result ) { - try { - $predis = new Predis(); - $predis->flush(); - } catch ( Exception $exception ) { - // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log - error_log( $exception ); - } + (new Predis)->flush(); } /** @@ -982,13 +976,7 @@ public function do_admin_actions() { $result = $wp_filesystem->delete( WP_CONTENT_DIR . '/object-cache.php' ); if ( $result ) { - try { - $predis = new Predis(); - $predis->flush(); - } catch ( Exception $exception ) { - // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log - error_log( $exception ); - } + (new Predis)->flush(); } /** diff --git a/includes/class-predis.php b/includes/class-predis.php index 2fe11c5d..8171bbb8 100644 --- a/includes/class-predis.php +++ b/includes/class-predis.php @@ -24,7 +24,7 @@ class Predis { * * @return void */ - public function connect() { + public function connect( $read_timeout = null ) { // Load bundled Predis library. if ( ! class_exists( '\Predis\Client' ) ) { require_once WP_REDIS_PLUGIN_PATH . '/dependencies/predis/predis/autoload.php'; @@ -39,7 +39,7 @@ public function connect() { 'port' => 6379, 'database' => 0, 'timeout' => 1, - 'read_timeout' => 1, + 'read_timeout' => $read_timeout ?? 1, ]; $settings = [ @@ -128,13 +128,26 @@ public function connect() { } /** - * Invalidate all items in the cache. + * Flushes the entire Redis database using the `WP_REDIS_FLUSH_TIMEOUT`. * - * @return bool True on success, false on failure. + * @param bool $throw_exception Whether to throw exception on error. + * @return bool */ - public function flush() { + public function flush( $throw_exception = false ) { + $flush_timeout = defined( 'WP_REDIS_FLUSH_TIMEOUT' ) + ? intval(WP_REDIS_FLUSH_TIMEOUT) + : 5; + if ( is_null( $this->redis ) ) { - $this->connect(); + try { + $this->connect( $flush_timeout ); + } catch ( Exception $exception ) { + if ( $throw_exception ) { + throw $exception; + } + + return false; + } } if ( defined( 'WP_REDIS_CLUSTER' ) ) { @@ -143,23 +156,46 @@ public function flush() { $this->redis->flushdb( $master ); } } catch ( Exception $exception ) { + if ( $throw_exception ) { + throw $exception; + } + return false; } - } else { - try { - $this->redis->flushdb(); - } catch ( Exception $exception ) { - return false; + + return true; + } + + try { + // TODO: test Predis return value... + + var_dump($this->redis->flushdb()); + exit; + + return $this->redis->flushdb(); + } catch ( Exception $exception ) { + if ( $throw_exception ) { + throw $exception; } + + return false; } + } - return true; + /** + * Flushes the entire Redis database using the `WP_REDIS_FLUSH_TIMEOUT` + * and will throw an exception if anything goes wrong. + * + * @return bool + */ + public function flushOrFail() { + return $this->flush( true ); } /** * Builds a clean connection array out of redis clusters array. * - * @return array + * @return array */ protected function build_cluster_connection_array() { $cluster = array_values( WP_REDIS_CLUSTER ); diff --git a/includes/cli/class-commands.php b/includes/cli/class-commands.php index 3c816f96..7628f616 100644 --- a/includes/cli/class-commands.php +++ b/includes/cli/class-commands.php @@ -173,20 +173,11 @@ public function update_dropin() { */ protected function flush_redis() { try { - $predis = new Predis(); - $predis->connect(); + return (new Predis)->flushOrFail(); } catch ( Exception $exception ) { - return $exception->getMessage(); - } + error_log( $exception ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log - try { - $predis->flush(); - } catch ( Exception $exception ) { - // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log - error_log( $exception ); + return $exception->getMessage(); } - - return true; } - } From e0b80a4bcc145e9f612287d6be9f4f6d840e030d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Till=20Kru=CC=88ss?= Date: Mon, 6 Nov 2023 09:56:18 -0800 Subject: [PATCH 2/3] strip [skip ci] --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 6ddc1407..6c14eb53 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,5 @@ # Redis Object Cache for WordPress -Update Banner: Fast load times; Less Database load; screenshots -Add: SpinupWP, BlueHost, LiquidWeb and other platforms that use it to the banner maybe also to the readme - A persistent object cache backend powered by Redis®¹. Supports [Predis](https://github.com/predis/predis/), [PhpRedis (PECL)](https://github.com/phpredis/phpredis), [Relay](https://relaycache.com), replication, sentinels, clustering and [WP-CLI](http://wp-cli.org/). [![Redis Object Cache screenshots](/.wordpress-org/collage-sm.jpg?raw=true)](/.wordpress-org/collage.png?raw=true) From 48b6406cf5defd3266632348582924e1acf2d951 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Till=20Kru=CC=88ss?= Date: Mon, 6 Nov 2023 10:57:14 -0800 Subject: [PATCH 3/3] wip --- CHANGELOG.md | 1 + FAQ.md | 8 ++++++++ README.md | 18 +++++++++--------- includes/class-plugin.php | 2 +- includes/class-predis.php | 12 +++++------- 5 files changed, 24 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01b65cd3..a91b55ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - Renamed `.redis-write-test.tmp` test file to `object-cache.tmp` - Call `redis_object_cache_error` action before `wp_die()` - Allow `WP_REDIS_PLUGIN_PATH` to be defined elsewhere +- Added experimental flush timeout (defaults to `5` seconds) ## 2.4.4 diff --git a/FAQ.md b/FAQ.md index cef2ee38..57f9a992 100644 --- a/FAQ.md +++ b/FAQ.md @@ -138,6 +138,14 @@ This can happen when Redis Server runs out of memory and no `maxmemory-policy` w Alternatively, you can set the `WP_REDIS_MAXTTL` constant to something relatively low (like `3600` seconds) and flush the cache.
+
+Flushing the cache causes timeout + +This can happen when the dataset in Redis Server is quite large. Consider increasing `WP_REDIS_READ_TIMEOUT` and `WP_REDIS_FLUSH_TIMEOUT` to 5-10 seconds. + +Alternatively, starting with Redis 6.2, setting the `lazyfree-lazy-user-flush` in the `redis.conf` configuration directive to `yes` changes the default flush mode to be asynchronous. +
+
Unable to flush the cache diff --git a/README.md b/README.md index 6c14eb53..1b6d3f92 100644 --- a/README.md +++ b/README.md @@ -36,13 +36,12 @@ The Redis Object Cache plugin comes with vast set of configuration options. If y | `WP_REDIS_PATH` | | The path to the unix socket of the Redis server | | `WP_REDIS_SCHEME` | `tcp` | The scheme used to connect: `tcp` or `unix` | | `WP_REDIS_DATABASE` | `0` | The database used by the cache: `0-15` | -| `WP_REDIS_PREFIX` | | The prefix used for all cache keys to avoid data collisions, replaces `WP_CACHE_KEY_SALT`. Should be human readable, not a "salt". | -| `WP_REDIS_PASSWORD` | | The password of the Redis server. Supports Redis ACLs arrays: `['user', 'password']` | +| `WP_REDIS_PREFIX` | | The prefix used for all cache keys to avoid data collisions (replaces `WP_CACHE_KEY_SALT`), should be human readable and not a "salt" | +| `WP_REDIS_PASSWORD` | | The password of the Redis server, supports Redis ACLs arrays: `['user', 'password']` | | `WP_REDIS_MAXTTL` | `0` | The maximum time-to-live of cache keys | -| `WP_REDIS_CLIENT` | | The client used to communicate with Redis. Defaults to `phpredis` when installed, otherwise `predis`. Supports `phpredis`, `predis`, `relay` | +| `WP_REDIS_CLIENT` | | The client used to communicate with Redis (defaults to `phpredis` when installed, otherwise `predis`), supports `phpredis`, `predis`, `relay` | | `WP_REDIS_TIMEOUT` | `1` | The connection timeout in seconds | | `WP_REDIS_READ_TIMEOUT` | `1` | The timeout in seconds when reading/writing | -| `WP_REDIS_FLUSH_TIMEOUT` | `5` | The timeout in seconds when flushing | | `WP_REDIS_IGNORED_GROUPS` | `[]` | Groups that should not be cached between requests in Redis |
@@ -51,7 +50,8 @@ The Redis Object Cache plugin comes with vast set of configuration options. If y | Configuration constant | Default | Description | | ------------------------------------ | ----------- | --------------------------------------------- | | `WP_CACHE_KEY_SALT` | | Deprecated. Replaced by `WP_REDIS_PREFIX` | -| `WP_REDIS_RETRY_INTERVAL` | | The number of milliseconds between retries | +| `WP_REDIS_FLUSH_TIMEOUT` | `5` | Experimental. The timeout in seconds when flushing | +| `WP_REDIS_RETRY_INTERVAL` | | The number of milliseconds between retries (PhpRedis only) | | `WP_REDIS_GLOBAL_GROUPS` | `[]` | Additional groups that are considered global on multisite networks | | `WP_REDIS_METRICS_MAX_TIME` | `3600` | The maximum number of seconds metrics should be stored | | `WP_REDIS_IGBINARY` | `false` | Whether to use the igbinary PHP extension for serialization | @@ -70,11 +70,11 @@ The Redis Object Cache plugin comes with vast set of configuration options. If y Options that exist, but **should not**, **may break without notice** in future releases and **won't receive any support** whatsoever from our team: -| Configuration constant | Default | Description | -| ----------------------------- | ----------- | ------------------------------------------------------------------- | +| Configuration constant | Default | Description | +| ----------------------------- | ----------- | --------------------------------------------------------------------- | | `WP_REDIS_GRACEFUL` | `false` | Prevents exceptions from being thrown, but will cause data corruption | -| `WP_REDIS_SELECTIVE_FLUSH` | `false` | Uses terribly slow Lua script for flushing | -| `WP_REDIS_UNFLUSHABLE_GROUPS` | `[]` | Uses terribly slow Lua script to prevent groups from being flushed | +| `WP_REDIS_SELECTIVE_FLUSH` | `false` | Uses terribly slow Lua script for flushing | +| `WP_REDIS_UNFLUSHABLE_GROUPS` | `[]` | Uses terribly slow Lua script to prevent groups from being flushed |
diff --git a/includes/class-plugin.php b/includes/class-plugin.php index b3651323..2ed728a7 100644 --- a/includes/class-plugin.php +++ b/includes/class-plugin.php @@ -1522,7 +1522,7 @@ public function on_deactivation( $plugin ) { wp_unschedule_event( $timestamp, 'rediscache_discard_metrics' ); } - wp_cache_flush(); + (new Predis)->flush(); if ( $this->validate_object_cache_dropin() && $this->initialize_filesystem( '', true ) ) { $wp_filesystem->delete( WP_CONTENT_DIR . '/object-cache.php' ); diff --git a/includes/class-predis.php b/includes/class-predis.php index 8171bbb8..3cb2339e 100644 --- a/includes/class-predis.php +++ b/includes/class-predis.php @@ -22,6 +22,7 @@ class Predis { /** * Connect to Redis. * + * @param int|null $read_timeout The read timeout in seconds. * @return void */ public function connect( $read_timeout = null ) { @@ -130,7 +131,7 @@ public function connect( $read_timeout = null ) { /** * Flushes the entire Redis database using the `WP_REDIS_FLUSH_TIMEOUT`. * - * @param bool $throw_exception Whether to throw exception on error. + * @param bool $throw_exception Whether to throw exception on error. * @return bool */ public function flush( $throw_exception = false ) { @@ -167,12 +168,7 @@ public function flush( $throw_exception = false ) { } try { - // TODO: test Predis return value... - - var_dump($this->redis->flushdb()); - exit; - - return $this->redis->flushdb(); + $this->redis->flushdb(); } catch ( Exception $exception ) { if ( $throw_exception ) { throw $exception; @@ -180,6 +176,8 @@ public function flush( $throw_exception = false ) { return false; } + + return true; } /**