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 20594f70..1b6d3f92 100644
--- a/README.md
+++ b/README.md
@@ -36,12 +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_READ_TIMEOUT` | `1` | The timeout in seconds when reading/writing |
| `WP_REDIS_IGNORED_GROUPS` | `[]` | Groups that should not be cached between requests in Redis |
@@ -50,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 |
@@ -69,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 047d980c..2ed728a7 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();
}
/**
@@ -1534,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 2fe11c5d..3cb2339e 100644
--- a/includes/class-predis.php
+++ b/includes/class-predis.php
@@ -22,9 +22,10 @@ class Predis {
/**
* Connect to Redis.
*
+ * @param int|null $read_timeout The read timeout in seconds.
* @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 +40,7 @@ public function connect() {
'port' => 6379,
'database' => 0,
'timeout' => 1,
- 'read_timeout' => 1,
+ 'read_timeout' => $read_timeout ?? 1,
];
$settings = [
@@ -128,13 +129,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 +157,43 @@ 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 {
+ $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;
}
-
}