-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: [Session] Redis session race condition #8323
Conversation
3fa9be3
to
b9b607a
Compare
I did simple testing on macOS, and the results was good.
|
b9b607a
to
7249361
Compare
Explanation of current --- a/system/Session/Handlers/RedisHandler.php
+++ b/system/Session/Handlers/RedisHandler.php
@@ -293,16 +293,25 @@ RedisHandler::lockSession()
$attempt = 0;
do {
+ // Gets the TTL of the lock record.
+ // When there is no lock record, if two processes query Redis at the same time,
+ // both will have `$ttl = 0`.
$ttl = $this->redis->ttl($lockKey);
assert(is_int($ttl));
if ($ttl > 0) {
+ // If the TTL is longer than zero second, that is the lock record exists,
+ // waits for one second.
sleep(1);
continue;
}
+ // Sets the lock record with TTL 300 seconds.
if (! $this->redis->setex($lockKey, 300, (string) Time::now()->getTimestamp())) {
+ // As long as the Redis server is working properly,
+ // the above command will never fail. So the following log will not be recorded.
+ // And if two processes have `$ttl = 0`, both will acquire the lock.
$this->logger->error('Session: Error while trying to obtain lock for ' . $this->keyPrefix . $sessionID);
return false;
@@ -334,6 +343,7 @@ RedisHandle::releaseLock()
{
if (isset($this->redis, $this->lockKey) && $this->lock) {
if (! $this->redis->del($this->lockKey)) {
+ // If two processes have the lock, latter one cannot delete the lock record.
$this->logger->error('Session: Error while trying to free lock for ' . $this->lockKey);
return false; |
When this fix will be releaed? |
As soon as possible when this PR is approved and merged. |
@kenjis the only thing I'd add is handling the Redis Exceptions or at least put those in PHPDoc |
9c1718b
to
a38ac8b
Compare
@najdanovicivan Added I also found that we cannot use Redis ACL.
If it is a bug, I will fix in this PR. |
229527b
to
a38ac8b
Compare
The return value (usually true on success, false on failure) https://www.php.net/manual/en/sessionhandlerinterface.close.php#refsect1-sessionhandlerinterface.close-returnvalues
a38ac8b
to
2fa55d4
Compare
@najdanovicivan Are you okay to merge this? If so, please approve. |
I sent #8578 to |
Description
Fixes #4391
Fixes #8567
close()
does not returnfalse
ifreleaseLock()
failedread()
does not returnfalse
iflockSession()
failedTesting
I have tested by
ab -n 1000 -c 20
.Results:
develop:
This PR:
Checklist: