amphp / redis

Efficient asynchronous communication with Redis servers, enabling scalable and responsive data storage and retrieval.

Home Page:https://amphp.org/redis

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Cannot write session to redis storage

maxwagner-dev opened this issue · comments

Hallo,

we use the amphp/http-server to run a Long-running PHP Webserver. For session handling we use the amphp/http-server-session package and this package to store session data in redis. Our system and solution works like expected, but after some time (6h-1d) the following error occurs when trying to create a new session and store it in redis:

Call to a member function write() on null
#0 [internal function]: Amp\Redis\RespSocket->Amp\Redis\{closure}()  
#1 /usr/share/app/vendor/amphp/amp/lib/Coroutine.php(67): Generator->current()  
#2 /usr/share/app/vendor/amphp/amp/lib/functions.php(96): Amp\Coroutine->__construct()
#3 /usr/share/app/vendor/amphp/redis/src/RespSocket.php(70): Amp\call()  
#4 /usr/share/app/vendor/amphp/redis/src/RemoteExecutor.php(74): Amp\Redis\RespSocket->write()  
#5 [internal function]: Amp\Redis\RemoteExecutor->Amp\Redis\{closure}()  
#6 /usr/share/app/vendor/amphp/amp/lib/Coroutine.php(67): Generator->current()  
#7 /usr/share/app/vendor/amphp/amp/lib/functions.php(96): Amp\Coroutine->__construct()  
#8 /usr/share/app/vendor/amphp/redis/src/RemoteExecutor.php(80): Amp\call()  
#9 /usr/share/app/vendor/amphp/redis/src/RemoteExecutor.php(55): Amp\Redis\RemoteExecutor->enqueue()  
#10 [internal function]: Amp\Redis\RemoteExecutor->Amp\Redis\{closure}()  
#11 /usr/share/app/vendor/amphp/amp/lib/Coroutine.php(118): Generator->send()
#12 /usr/share/app/vendor/amphp/amp/lib/Internal/Placeholder.php(46): Amp\Coroutine->Amp\{closure}()
#13 /usr/share/app/vendor/amphp/amp/lib/Coroutine.php(151): Amp\Coroutine->onResolve()
#14 /usr/share/app/vendor/amphp/amp/lib/functions.php(96): Amp\Coroutine->__construct()
#15 /usr/share/app/vendor/amphp/redis/src/RemoteExecutor.php(62): Amp\call()
#16 /usr/share/app/vendor/amphp/redis/src/Redis.php(1101): Amp\Redis\RemoteExecutor->execute()
#17 [internal function]: Amp\Redis\Redis->Amp\Redis\{closure}()
#18 /usr/share/app/vendor/amphp/amp/lib/Coroutine.php(67): Generator->current()
#19 /usr/share/app/vendor/amphp/amp/lib/functions.php(96): Amp\Coroutine->__construct()
#20 /usr/share/app/vendor/amphp/redis/src/Redis.php(1110): Amp\call()
#21 /usr/share/app/vendor/amphp/redis/src/Mutex/Mutex.php(170): Amp\Redis\Redis->eval()
#22 [internal function]: Amp\Redis\Mutex\Mutex->Amp\Redis\Mutex\{closure}()
#23 /usr/share/app/vendor/amphp/amp/lib/Coroutine.php(67): Generator->current()
#24 /usr/share/app/vendor/amphp/amp/lib/functions.php(96): Amp\Coroutine->__construct()
#25 /usr/share/app/vendor/amphp/redis/src/Mutex/Mutex.php(199): Amp\call()
#26 /usr/share/app/vendor/amphp/http-server-session/src/Session.php(147): Amp\Redis\Mutex\Mutex->acquire()
#27 [internal function]: Amp\Http\Server\Session\Session->Amp\Http\Server\Session\{closure}()
#28 /usr/share/app/vendor/amphp/amp/lib/Coroutine.php(67): Generator->current()
#29 /usr/share/app/vendor/amphp/amp/lib/functions.php(96): Amp\Coroutine->__construct()
#30 /usr/share/app/vendor/amphp/http-server-session/src/Session.php(328): Amp\call()
#31 [internal function]: Amp\Http\Server\Session\Session->Amp\Http\Server\Session\{closure}()
#32 /usr/share/app/vendor/amphp/amp/lib/Coroutine.php(118): Generator->send()
#33 /usr/share/app/vendor/amphp/amp/lib/Success.php(41): Amp\Coroutine->Amp\{closure}()
#34 /usr/share/app/vendor/amphp/amp/lib/Coroutine.php(151): Amp\Success->onResolve()
#35 /usr/share/app/vendor/amphp/amp/lib/functions.php(96): Amp\Coroutine->__construct()
#36 /usr/share/app/vendor/amphp/http-server-session/src/Session.php(329): Amp\call()
#37 /usr/share/app/vendor/amphp/http-server-session/src/Session.php(163): Amp\Http\Server\Session\Session->synchronized()
#38 OWN_CLASS_FOR_SESSION_OPENING(48): Amp\Http\Server\Session\Session->open()

Here is our setup for the session driver:

$sessionSerializer = new CompressingSerializeSerializer();
$host = 'someHost';
$port = 6379;
$pass = 'somePassword';

$redisConfig = Config::fromUri('redis://' . $host . ':' . $port);
if ($pass) {
	$redisConfig = $redisConfig->withPassword($pass);
}

$remoteExecutorFactory = new RemoteExecutorFactory($redisConfig);
$redisSessionStorage = new RedisStorage($remoteExecutorFactory, $sessionSerializer, $sessionConfig->getTtlSeconds());
$sessionStorage = $redisSessionStorage;
$keyedMutex = new Mutex($remoteExecutorFactory);
$idGenerator = new DefaultIdGenerator();
$sessionDriver = new Driver($keyedMutex, $sessionStorage, $idGenerator);

Until now i could not find a setup to manually force this error.
Thank you in advance!

This might happen if the connection gets closed.

What would be the best way to keep the connection alive over time? Using a loop to recreate the driver every few minutes / hours?

@maxwagner-dev It should reconnect automatically. If you see this failure it fails permanently I guess?

@kelunik Yes, this error occurred multiple times / one time a day over the last 14 days of testing.

@kelunik I have implemented your latest release. It's running without any error over the last two days.

You can close the issue.
Thank you very much for the fast solution.

@maxwagner-dev Thanks for confirming it works as expected now. If you'd like to support our work, you can sponsor us, especially if you're using Amp commercially. :-)