Make having redis offline more survivable.
This commit is contained in:
parent
14da1e0513
commit
b8bb6757a8
4 changed files with 79 additions and 27 deletions
|
|
@ -14,6 +14,7 @@
|
|||
},
|
||||
"require": {
|
||||
"php": ">=7.4",
|
||||
"ext-apcu": "*",
|
||||
"ext-curl": "*",
|
||||
"ext-json": "*",
|
||||
"ext-openssl": "*",
|
||||
|
|
|
|||
18
src/App.php
18
src/App.php
|
|
@ -254,7 +254,7 @@ class App
|
|||
return $faker;
|
||||
});
|
||||
|
||||
$container->set(CachePoolChain::class, function (\Redis $redis) {
|
||||
$container->set(CachePoolChain::class, function (Redis $redis) {
|
||||
$caches = [];
|
||||
|
||||
// If apc/apcu present, add it to the pool
|
||||
|
|
@ -265,7 +265,9 @@ class App
|
|||
}
|
||||
|
||||
// If Redis is configured, add it to the pool.
|
||||
$caches[] = new RedisCachePool($redis);
|
||||
if($redis->isAvailable()) {
|
||||
$caches[] = new RedisCachePool($redis);
|
||||
}
|
||||
$caches[] = new ArrayCachePool();
|
||||
|
||||
return new CachePoolChain($caches);
|
||||
|
|
@ -287,13 +289,15 @@ class App
|
|||
return $monolog;
|
||||
});
|
||||
|
||||
$container->set(\Redis::class, function (EnvironmentService $environmentService) {
|
||||
$redis = new Redis();
|
||||
$redis->connect(
|
||||
$container->set(Redis::class, function (EnvironmentService $environmentService) {
|
||||
return (new Redis(
|
||||
$environmentService->get('REDIS_HOST', 'redis'),
|
||||
$environmentService->get('REDIS_PORT', 6379)
|
||||
);
|
||||
$environmentService->get('REDIS_PORT', 6379),
|
||||
$environmentService->get('REDIS_TIMEOUT', 0.0)
|
||||
));
|
||||
});
|
||||
|
||||
$container->set(\Redis::class, function(Redis $redis){
|
||||
return $redis;
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -4,11 +4,34 @@ namespace Benzine\Redis;
|
|||
|
||||
class Redis extends \Redis
|
||||
{
|
||||
private string $host;
|
||||
private int $port;
|
||||
private int $timeout;
|
||||
|
||||
public function __construct($host, $port = 6379, $timeout = 0.0)
|
||||
{
|
||||
$this->host = $host;
|
||||
$this->port = $port;
|
||||
$this->timeout = $timeout;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function isAvailable() : bool
|
||||
{
|
||||
try {
|
||||
$this->ping('am I human?');
|
||||
return true;
|
||||
}catch(\RedisException $redisException){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** @var Lua\AbstractLuaExtension[] */
|
||||
private array $scripts;
|
||||
|
||||
public function __call($name, $arguments)
|
||||
{
|
||||
\Kint::dump($name, $arguments);exit;
|
||||
foreach ($this->scripts as $script) {
|
||||
foreach ($script->getFunctionNames() as $functionName) {
|
||||
if (strtolower($name) == strtolower($functionName)) {
|
||||
|
|
@ -20,6 +43,15 @@ class Redis extends \Redis
|
|||
}
|
||||
}
|
||||
|
||||
public function get($key)
|
||||
{
|
||||
if(!$this->isConnected()){
|
||||
parent::pconnect($this->host, $this->port, $this->timeout);
|
||||
$this->initialiseExtensions();
|
||||
}
|
||||
parent::get($key); // TODO: Change the autogenerated stub
|
||||
}
|
||||
|
||||
public function initialiseExtensions(): void
|
||||
{
|
||||
$this->scripts[] = new Lua\SetIfHigher($this);
|
||||
|
|
@ -30,7 +62,6 @@ class Redis extends \Redis
|
|||
|
||||
public function connect($host, $port = 6379, $timeout = 0.0, $reserved = null, $retryInterval = 0, $readTimeout = 0.0): void
|
||||
{
|
||||
parent::connect($host, $port, $timeout, $reserved, $retryInterval, $readTimeout);
|
||||
$this->initialiseExtensions();
|
||||
throw new \RedisException("Do not directly call connect()");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,15 +2,18 @@
|
|||
|
||||
namespace Benzine\Services;
|
||||
|
||||
use Benzine\Redis\Redis;
|
||||
|
||||
class SessionService implements \SessionHandlerInterface
|
||||
{
|
||||
protected \Redis $redis;
|
||||
protected Redis $redis;
|
||||
private ?bool $redisIsAvailable = null;
|
||||
protected $oldID;
|
||||
|
||||
private int $lifetime = 43200;
|
||||
private array $dirtyCheck = [];
|
||||
|
||||
public function __construct(\Redis $redis)
|
||||
public function __construct(Redis $redis)
|
||||
{
|
||||
$this->redis = $redis;
|
||||
}
|
||||
|
|
@ -72,6 +75,13 @@ class SessionService implements \SessionHandlerInterface
|
|||
return true;
|
||||
}
|
||||
|
||||
public function useRedis() : bool {
|
||||
if($this->redisIsAvailable === null){
|
||||
$this->redisIsAvailable = $this->redis->isAvailable();
|
||||
}
|
||||
return $this->redisIsAvailable;
|
||||
}
|
||||
|
||||
public function read($session_id)
|
||||
{
|
||||
if ($this->useAPCU()) {
|
||||
|
|
@ -84,16 +94,17 @@ class SessionService implements \SessionHandlerInterface
|
|||
$session_id = $this->oldID ? $this->oldID : $session_id;
|
||||
}
|
||||
|
||||
$serialised = $this->redis->get("session:{$session_id}");
|
||||
if (null != $serialised) {
|
||||
if (!empty($this->oldID)) {
|
||||
// clean up old session after regenerate
|
||||
$this->redis->del("session:{$session_id}");
|
||||
$this->oldID = null;
|
||||
$result = '';
|
||||
if($this->useRedis()) {
|
||||
$serialised = $this->redis->get("session:{$session_id}");
|
||||
if (null != $serialised) {
|
||||
if (!empty($this->oldID)) {
|
||||
// clean up old session after regenerate
|
||||
$this->redis->del("session:{$session_id}");
|
||||
$this->oldID = null;
|
||||
}
|
||||
$result = unserialize($serialised);
|
||||
}
|
||||
$result = unserialize($serialised);
|
||||
} else {
|
||||
$result = '';
|
||||
}
|
||||
|
||||
if ($this->useAPCU()) {
|
||||
|
|
@ -105,19 +116,27 @@ class SessionService implements \SessionHandlerInterface
|
|||
return $result;
|
||||
}
|
||||
|
||||
public function write($session_id, $session_data)
|
||||
/**
|
||||
* @param string $session_id
|
||||
* @param string $session_data
|
||||
* @return bool Always returns true.
|
||||
*/
|
||||
public function write($session_id, $session_data) : bool
|
||||
{
|
||||
$dirty = false;
|
||||
if ($this->useAPCU()) {
|
||||
$dirty = crc32(apcu_fetch('read-'.$session_id)) != crc32($session_data);
|
||||
} else {
|
||||
$dirty = $this->dirtyCheck['read-'.$session_id] != crc32($session_data);
|
||||
}
|
||||
if ($dirty) {
|
||||
|
||||
if ($this->useRedis() && $dirty) {
|
||||
$this->redis->set("session:{$session_id}", serialize($session_data));
|
||||
$this->redis->expire("session:{$session_id}", $this->getLifetime());
|
||||
}
|
||||
apcu_store('read-'.$session_id, $session_data);
|
||||
|
||||
if($this->useAPCU()) {
|
||||
apcu_store('read-' . $session_id, $session_data);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -180,9 +199,6 @@ class SessionService implements \SessionHandlerInterface
|
|||
|
||||
private function useAPCU(): bool
|
||||
{
|
||||
// @todo fix apcu damnit
|
||||
return false;
|
||||
|
||||
return function_exists('apcu_store');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue