When using redis-8.x-1.0 also als lock backend, method lockMayBeAvailable of classes \Drupal\redis\Lock\Predis and \Drupal\redis\Lock\PhpRedis always returns FALSE, since its return condition compares the lookup result type-safe with FALSE in case of a non-existing keym but the line `$this->client->get($key)` will return NULL in case of a key not found (at least in my case, local as well as on platform.sh). This e.g. leads to the config imported abort with a '[warning] Another request may be synchronizing configuration already.' when trying to import a config.
The patch in this issue aims to resolve this issue by extending the return condition to work with both FALSE as well as NULL.
1. Can someone reproduce the problem?
2. Please review and comment.
| Comment | File | Size | Author |
|---|---|---|---|
| #11 | 2996655-11.patch | 4.15 KB | sardara |
| #11 | interdiff-2996655-2-11.txt | 2.94 KB | sardara |
| #2 | lockMayBeAvailable-always-fails-2996655-2.patch | 1017 bytes | danielnolde |
| #16 | interdiff-2996655-11-16.txt | 3.71 KB | sardara |
| #16 | 2996655-16.patch | 4.78 KB | sardara |
Comments
Comment #2
danielnolde commentedComment #3
claudiu.cristeaWe have the same symptom when syncing config. Disabling Redis during config sync fixes the issue.
Comment #4
sardara commentedTried the patch locally as our project is facing the same issue (as @claudiu.cristea said).
Patch solves the issue.
The issue has been reproduced using the predis library, but indeed should be the same with the phpredis backend.
As @danielnolde said, Redis returns NULL for non-existing keys (see https://redis.io/commands/get).
Comment #5
claudiu.cristeaComment #6
sardara commentedCurrent tests are not running correctly, see #3002634: RedisLockFunctionalTest is running with database lock implementations.
Even with that fixed, the current lock tests are extending core ones, which don't cover the case of a lock checked for availability when not acquired yet, it seems.
Attaching patch with a (temporary) test to outline the issue. Note that patch from #3002634-2: RedisLockFunctionalTest is running with database lock implementations needs to be applied.
I wrote temporary as the test written doesn't belong to that BrowserTest, it should be moved to a kernel for how it is written.
Or it could be ditched when #3002640: Improve test coverage for LockBackendInterface::lockMayBeAvailable() is in.
Comment #7
sardara commentedComment #8
claudiu.cristeaThis comment looks odd.
Can we write this more simple, as
return !$value? I have no idea if the value could be "" (empty string) or 0 and, if yes, such values have the same meaning (ie lock is available).Yes, this belongs to #3002640: Improve test coverage for LockBackendInterface::lockMayBeAvailable(). I think we should:
How it sounds?
EDIT: Or just add the same kernel test here and change it after the twin one goes in core.
Comment #9
claudiu.cristeaAdd related issues.
Comment #10
sardara commentedAs @claudiu.cristea suggested I'm attaching the two cumulative patches that include #3002634: RedisLockFunctionalTest is running with database lock implementations:
Since this issue needs #3002634: RedisLockFunctionalTest is running with database lock implementations to be merged in order to run the tests, I'll avoid providing the non-cumulative patch for now, unless requested.
Putting up for a first round of review.
I'll address also the first comment from @claudiu.cristea tomorrow, I missed it now.
Comment #11
sardara commentedActually it looks very painful to understand what has been added in the cumulative patch.
Attaching a patch with this issue code only (but still needs to be applied on top of the #3002634).
Comment #12
sardara commentedNoticed that I have wrongly used
lock_ain the testtestPersistentLock(). It needs to belock1.I'll fix it this evening.
Comment #13
claudiu.cristea#10.1:
I think we should just drop it. It's unusual to have comment referring an older version of Drupal.
#10.2: Well, my understanding is that the Redis client is trying to get the object from the backend (which in our case is the lock entry). A valid lock would be a "non-empty" value. So, my common sense, whispers that returning
!$value(orempty($value)) is OK. At least let's try and see what other reviewers or the module maintainer are saying. It would be a cleaner approach.#11:
I know. The idea was just to run tests on Travis CI with cumulative patch in order to prove the fix works and then paste the test URLs here so that the module maintainer is able to see the "test only" failing and the full patch passing.
EDIT: Actually we're not blocked anymore on #3002634: RedisLockFunctionalTest is running with database lock implementations as we've been migrated to a Kernel test. So, just running the tests on Travis CI and pasting here the 2 links would be enough.
Comment #14
claudiu.cristeaMore review.
Nit: When the method contains only few lines we can drop the empty line. It's more readable. (not mandatory)
Starting with PHP 5.5, the magic class name constant
::classwas introduced. That is the preferred way to refer the class name as is more readable and if, for some reasons, the class namespace changes it would be easier to port the code.Let's add a comment here, explaining what we're testing.
Actually, in #3002640: Improve test coverage for LockBackendInterface::lockMayBeAvailable() this will be part of
LockTest::testBackendLockRelease(), probably as the first line there. So it makes sense to keep it aslock_a(?). Let's add also a TODO:Comment #15
sardara commentedComment #16
sardara commentedUpdating the patches to fix the remarks and two bad copy-pastes from my side.
Addressing first review from @claudiu.cristea:
uniqid(), so a boolean cast should be enough.Regarding the combined patch, I expressed myself badly. I absolutely agree with the combined patch approach :) I added also the final patch to understand better which code is in scope of this issue alone.
Now addressing comments from #14: agree on everything. Just on point 4, I changed the
lock_aas it was a bad copy-paste from the kernel test. I changed the names to reflect the ones used in the parent test.Cumulative patches test results:
Link to the PR in Github: https://github.com/brummbar/redis/pull/2 .
Comment #17
claudiu.cristeaGreat!
Comment #18
claudiu.cristeaSorry, I think that it should be postponed on #3002634: RedisLockFunctionalTest is running with database lock implementations.
Comment #19
berdirStrange, I never saw these problems and I also can't make those tests fail. $value is FALSE when I'm debugging the test. PHP 7.2.10, php info says Redis 3.1.6 while info server in my redis server says 4.0.9. We're also using platform.sh in all our D8 projects and it also works fine for us there.
https://github.com/phpredis/phpredis#return-value-21 is also documented as returning FALSE.
I'm fine with committing this but it would be nice to understand what the change here is exactly?
Comment #20
sardara commented@Berdir the error occurs only when using the Predis library.
When asking a non-existing lock, a
getcommand will be executed on the key. By specifications of Redis, aNILresponse will be returned.The response will be
$-1, which will be decoded by Predis\Predis\Connection\StreamConnection::read()function to NULL (line 328).It seems that Phpredis instead returns FALSE.
So if you prefer, we can revert the changes in the Phpredis client and leave the null comparison only for the Predis client.
Comment #21
claudiu.cristeaI think we can safely test for
empty($value)in both.Comment #23
berdirThanks, committed.
Comment #24
claudiu.cristeaI did the review here but still left out from credits :(
Comment #25
berdir