Commit f8e2383b authored by Marcus Boon's avatar Marcus Boon
Browse files

MDL-59866 session: Add retry for redis sessions

There is an edge case whereby redis will fail
to accept connections on the first try but
retrying the connection seems to make it work

Included in this commit:
* Retry functionality in the session init
parent 109aa076
...@@ -157,39 +157,61 @@ class redis extends handler { ...@@ -157,39 +157,61 @@ class redis extends handler {
throw new exception('redissessionhandlerproblem', 'error'); throw new exception('redissessionhandlerproblem', 'error');
} }
try { // MDL-59866: Add retries for connections (up to 5 times) to make sure it goes through.
// One second timeout was chosen as it is long for connection, but short enough for a user to be patient. $counter = 1;
if (!$this->connection->connect($this->host, $this->port, 1)) { $maxnumberofretries = 5;
throw new RedisException('Unable to connect to host.');
} while ($counter <= $maxnumberofretries) {
try {
$delay = rand(100000, 500000);
if ($this->auth !== '') { // One second timeout was chosen as it is long for connection, but short enough for a user to be patient.
if (!$this->connection->auth($this->auth)) { if (!$this->connection->connect($this->host, $this->port, 1, null, $delay)) {
throw new RedisException('Unable to authenticate.'); throw new RedisException('Unable to connect to host.');
} }
}
if (!$this->connection->setOption(\Redis::OPT_SERIALIZER, $this->serializer)) { if ($this->auth !== '') {
throw new RedisException('Unable to set Redis PHP Serializer option.'); if (!$this->connection->auth($this->auth)) {
} throw new RedisException('Unable to authenticate.');
}
}
if ($this->prefix !== '') { if (!$this->connection->setOption(\Redis::OPT_SERIALIZER, $this->serializer)) {
// Use custom prefix on sessions. throw new RedisException('Unable to set Redis PHP Serializer option.');
if (!$this->connection->setOption(\Redis::OPT_PREFIX, $this->prefix)) {
throw new RedisException('Unable to set Redis Prefix option.');
} }
}
if ($this->database !== 0) { if ($this->prefix !== '') {
if (!$this->connection->select($this->database)) { // Use custom prefix on sessions.
throw new RedisException('Unable to select Redis database '.$this->database.'.'); if (!$this->connection->setOption(\Redis::OPT_PREFIX, $this->prefix)) {
throw new RedisException('Unable to set Redis Prefix option.');
}
}
if ($this->database !== 0) {
if (!$this->connection->select($this->database)) {
throw new RedisException('Unable to select Redis database '.$this->database.'.');
}
} }
$this->connection->ping();
return true;
} catch (RedisException $e) {
$logstring = "Failed to connect (try {$counter} out of {$maxnumberofretries}) to redis ";
$logstring .= "at {$this->host}:{$this->port}, error returned was: {$e->getMessage()}";
// @codingStandardsIgnoreStart
error_log($logstring);
// @codingStandardsIgnoreEnd
} }
$this->connection->ping();
return true; $counter++;
} catch (RedisException $e) {
error_log('Failed to connect to redis at '.$this->host.':'.$this->port.', error returned was: '.$e->getMessage()); // Introduce a random sleep between 100ms and 500ms.
return false; usleep(rand(100000, 500000));
} }
// We have exhausted our retries, time to give up.
return false;
} }
/** /**
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment