Skip to content

Commit 8401bac

Browse files
authored
Merge pull request #2060 from MohKari/mohkari/develop
Cache Drive Backups
2 parents 10e689f + 94554b9 commit 8401bac

4 files changed

Lines changed: 102 additions & 33 deletions

File tree

system/Cache/CacheFactory.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
namespace CodeIgniter\Cache;
4040

4141
use CodeIgniter\Cache\Exceptions\CacheException;
42+
use CodeIgniter\Exceptions\CriticalError;
4243

4344
/**
4445
* Class Cache
@@ -93,7 +94,20 @@ public static function getHandler($config, string $handler = null, string $backu
9394
}
9495
}
9596

96-
$adapter->initialize();
97+
// If $adapter->initialization throws a CriticalError exception, we will attempt to
98+
// use the $backup handler, if that also fails, we resort to the dummy handler.
99+
try
100+
{
101+
$adapter->initialize();
102+
}
103+
catch (CriticalError $e)
104+
{
105+
// log the fact that an exception occurred as well what handler we are resorting to
106+
log_message('critical', $e->getMessage() . ' Resorting to using ' . $backup . ' handler.');
107+
108+
// get the next best cache handler (or dummy if the $backup also fails)
109+
$adapter = self::getHandler($config, $backup, 'dummy');
110+
}
97111

98112
return $adapter;
99113
}

system/Cache/Handlers/MemcachedHandler.php

Lines changed: 55 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -115,35 +115,68 @@ public function __destruct()
115115
*/
116116
public function initialize()
117117
{
118-
if (class_exists('\Memcached'))
118+
// Try to connect to Memcache or Memcached, if an issue occurs throw a CriticalError exception,
119+
// so that the CacheFactory can attempt to initiate the next cache handler.
120+
try
119121
{
120-
$this->memcached = new \Memcached();
121-
if ($this->config['raw'])
122+
if (class_exists('\Memcached'))
122123
{
123-
$this->memcached->setOption(\Memcached::OPT_BINARY_PROTOCOL, true);
124+
// Create new instance of \Memcached
125+
$this->memcached = new \Memcached();
126+
if ($this->config['raw'])
127+
{
128+
$this->memcached->setOption(\Memcached::OPT_BINARY_PROTOCOL, true);
129+
}
130+
131+
// Add server
132+
$this->memcached->addServer(
133+
$this->config['host'], $this->config['port'], $this->config['weight']
134+
);
135+
136+
// attempt to get status of servers
137+
$stats = $this->memcached->getStats();
138+
139+
// $stats should be an associate array with a key in the format of host:port.
140+
// If it doesn't have the key, we know the server is not working as expected.
141+
if( !isset($stats[$this->config['host']. ':' .$this->config['port']]) )
142+
{
143+
throw new CriticalError('Cache: Memcached connection failed.');
144+
}
124145
}
125-
}
126-
elseif (class_exists('\Memcache'))
127-
{
128-
$this->memcached = new \Memcache();
129-
}
130-
else
131-
{
132-
throw new CriticalError('Cache: Not support Memcache(d) extension.');
133-
}
146+
elseif (class_exists('\Memcache'))
147+
{
148+
// Create new instance of \Memcache
149+
$this->memcached = new \Memcache();
134150

135-
if ($this->memcached instanceof \Memcached)
151+
// Check if we can connect to the server
152+
$can_connect = $this->memcached->connect(
153+
$this->config['host'], $this->config['port']
154+
);
155+
156+
// If we can't connect, throw a CriticalError exception
157+
if($can_connect == false){
158+
throw new CriticalError('Cache: Memcache connection failed.');
159+
}
160+
161+
// Add server, third parameter is persistence and defaults to TRUE.
162+
$this->memcached->addServer(
163+
$this->config['host'], $this->config['port'], true, $this->config['weight']
164+
);
165+
}
166+
else
167+
{
168+
throw new CriticalError('Cache: Not support Memcache(d) extension.');
169+
}
170+
}
171+
catch (CriticalError $e)
136172
{
137-
$this->memcached->addServer(
138-
$this->config['host'], $this->config['port'], $this->config['weight']
139-
);
173+
// If a CriticalError exception occurs, throw it up.
174+
throw $e;
140175
}
141-
elseif ($this->memcached instanceof \Memcache)
176+
catch (\Exception $e)
142177
{
143-
// Third parameter is persistence and defaults to TRUE.
144-
$this->memcached->addServer(
145-
$this->config['host'], $this->config['port'], true, $this->config['weight']
146-
);
178+
// If an \Exception occurs, convert it into a CriticalError exception and throw it.
179+
throw new CriticalError('Cache: Memcache(d) connection refused (' . $e->getMessage() . ').');
147180
}
148181
}
149182

system/Cache/Handlers/PredisHandler.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ public function __construct($config)
9999
*/
100100
public function initialize()
101101
{
102+
// Try to connect to Redis, if an issue occurs throw a CriticalError exception,
103+
// so that the CacheFactory can attempt to initiate the next cache handler.
102104
try
103105
{
104106
// Create a new instance of Predis\Client
@@ -110,7 +112,7 @@ public function initialize()
110112
catch (\Exception $e)
111113
{
112114
// thrown if can't connect to redis server.
113-
throw new CriticalError('Cache: Predis connection refused (' . $e->getMessage() . ')');
115+
throw new CriticalError('Cache: Predis connection refused (' . $e->getMessage() . ').');
114116
}
115117
}
116118

system/Cache/Handlers/RedisHandler.php

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
namespace CodeIgniter\Cache\Handlers;
4040

4141
use CodeIgniter\Cache\CacheInterface;
42+
use CodeIgniter\Exceptions\CriticalError;
4243

4344
/**
4445
* Redis cache handler
@@ -116,19 +117,38 @@ public function initialize()
116117
$config = $this->config;
117118

118119
$this->redis = new \Redis();
119-
if (! $this->redis->connect($config['host'], ($config['host'][0] === '/' ? 0 : $config['port']), $config['timeout']))
120-
{
121-
log_message('error', 'Cache: Redis connection failed. Check your configuration.');
122-
}
123120

124-
if (isset($config['password']) && ! $this->redis->auth($config['password']))
121+
// Try to connect to Redis, if an issue occurs throw a CriticalError exception,
122+
// so that the CacheFactory can attempt to initiate the next cache handler.
123+
try
125124
{
126-
log_message('error', 'Cache: Redis authentication failed.');
125+
// Note:: If Redis is your primary cache choice, and it is "offline", every page load will end up been delayed by the timeout duration.
126+
// 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.
127+
128+
if (! $this->redis->connect($config['host'], ($config['host'][0] === '/' ? 0 : $config['port']), $config['timeout']))
129+
{
130+
// Note:: I'm unsure if log_message() is necessary, however I'm not 100% comfortable removing it.
131+
log_message('error', 'Cache: Redis connection failed. Check your configuration.');
132+
throw new CriticalError('Cache: Redis connection failed. Check your configuration.');
133+
}
134+
135+
if (isset($config['password']) && ! $this->redis->auth($config['password']))
136+
{
137+
log_message('error', 'Cache: Redis authentication failed.');
138+
throw new CriticalError('Cache: Redis authentication failed.');
139+
}
140+
141+
if (isset($config['database']) && ! $this->redis->select($config['database']))
142+
{
143+
log_message('error', 'Cache: Redis select database failed.');
144+
throw new CriticalError('Cache: Redis select database failed.');
145+
}
127146
}
128-
129-
if (isset($config['database']) && ! $this->redis->select($config['database']))
147+
catch (\RedisException $e)
130148
{
131-
log_message('error', 'Cache: Redis select database failed.');
149+
// $this->redis->connect() can sometimes throw a RedisException.
150+
// We need to convert the exception into a CriticalError exception and throw it.
151+
throw new CriticalError('Cache: RedisException occurred with message (' . $e->getMessage() . ').');
132152
}
133153
}
134154

0 commit comments

Comments
 (0)