Redis Cache By Xon

Redis Cache By Xon 2.18.7

No permission to download
I think this would be on XF to redesign the way they do caching, not this add-on.

if it can't pull from the cache after a retry, it should compute/pull direct and send an alert of some sort "Hey admin, cache hit failed at X time".

Yes, I agree. I just wanted to reconfirm with @Xon that my expectations that XenForo should fallback gracefully if Redis (or any caching instance) wasn't out of line before moving on to report this "bug" with caching.

Edit: From what I can tell the fatal CredisException is thrown directly from Credis_Client->connect() inside the add-on’s code (Client.php line ~607).The add-on is the one deciding how to handle (or not handle) connection failures. SV\RedisCache\SymfonyCache\Redis.php is already intercepting calls (e.g., getItems, mGet) and timing them. It would be straightforward for the add-on to wrap the initial connect() call in a try/catch block and, on failure, return a fallback cache provider (e.g., a NullCache, ArrayCache, or XenForo’s default FileCache).

XenForo expects the cache object (from config['cache']['provider']) to behave like PSR-16 SimpleCache — i.e., it should never throw exceptions on get/set/delete when the backend is unavailable; it should return null/false or a default value gracefully.Most production Redis cache libraries (e.g., Symfony’s RedisAdapter, Laravel’s Redis store) do exactly that: they catch connection errors and degrade silently or fall back. Credis itself is quite low-level and throws aggressively — that would make this add-on responsible for adding that resilience layer.

Something like...
PHP:
public function getItems(array $keys)
{
    try {
        if (!$this->redis->isConnected()) {
            $this->redis->connect(...);  // or reconnect logic
        }
        return $this->redis->mGet($keys);
    } catch (CredisException $e) {
        // Log once: "Redis unavailable, falling back to file cache"
        $this->fallbackCache = $this->createFallbackCache(); // e.g. FileCache or NullCache
        return $this->fallbackCache->getItems($keys);
    }
}
// Similar try/catch around set, delete, clear, has, etc.

This could be done on first failure, then to fallback and stay there until Redis is detected alive again (periodic health check). This would prevent the site-wide fatals like I experienced during Redis restarts/outages.
 
Last edited:
Blindly using a failback caching adaptor is an incredible bad idea. And it is not a feature I will add or expect XF to add.

Which now appears to be a fundamental issue with XenForo's implementation of Redis.
XenForo uses a paper thin wrapper around Symfony’s RedisAdapter, which uses phpredis. The RedisAdapter could use predis, but XF doesn't provide a way to load that library without 3rd party code

This add-on provides a caching adapter which is a thin wrapper around the credis library, which implements the redis text-based protocol in pure php but optionally supports phpredis.

XenForo expects the cache object (from config['cache']['provider']) to behave like PSR-16 SimpleCache — i.e., it should never throw exceptions on get/set/delete when the backend is unavailable;
That is incorrect. Nothing in the PSR-16 spec says that, at all

Most production Redis cache libraries (e.g., Symfony’s RedisAdapter, Laravel’s Redis store) do exactly that: they catch connection errors and degrade silently or fall back.
The add-on has a basic form of retry on a new connection failed logic, it just isn't very useful as it doesn't stall for the better part of a second to wait for redis to come back.

While Symfony’s RedisAdapter/Laravel’s Redis use PhpRedis or predis, and Laravel uses PhpRedis's retry new connection logic they absolutely don't silently degrade or return failure if the connection to the caching backend stops working.

Both PhpRedis and predis will aggressively throw exception, and neither Symfony's or Laravel's wrapper layers will catch most exceptions. There are some edge cases where Laravel will swallow exceptions when using the pipelining feature but depending on the exception this will leave the connection between php and redis in a broken state, so lol.
 
Last edited:
@Xon, thanks for the detailed explanation — I really appreciate you taking the time.

Everything you said aligns with how Credis, phpredis/Predis, Symfony RedisAdapter, and Laravel behave in practice. I appreciate the correction on PSR-16 (no prohibition on throwing for connection failures) and the confirmation that aggressive exceptions are standard/expected in these clients.

You're also right that "blind" automatic fallback would be risky — it could lead to inconsistent data, hard-to-debug performance regressions, or overload on the DB/filesystem during outages. I’m not asking to change the default behavior or make silent fallback mandatory.

What I'm running into (and a couple others have mentioned in similar threads) is that even brief Redis downtime (e.g., 30–60 seconds during a restart or host glitch) takes the entire site offline with a fatal CredisException early in bootstrap (DataRegistry load). For a forum, like XenForo, that's very noticeable as nothing is reachable during that time.

Would you be open to an 'opt-in config option' (default 'throw', no change to current behavior) that lets admins choose a fallback provider class on connect failure?

In config.php something like:
PHP:
$config['cache']['config']['on_connect_failure'] = 'throw';        // default: current behavior
// or
$config['cache']['config']['on_connect_failure'] = 'Filesystem';   // switch to XenForo's built-in Filesystem provider
// or
$config['cache']['config']['on_connect_failure'] = 'NullAdapter';  // no-op cache for the request (get returns empty/false)
// or perhaps a custom class name if someone wants their own

Thanks again.
 
Back
Top Bottom