Closed Byter09 closed 6 years ago
Hey @Byter09
I see, that you use BLPOP in your method RedisList:: brpop
.
Please read very carefully about Redis command BLPOP - Blocking behavior Note:
If none of the specified keys exist, BLPOP blocks the connection until another client performs an LPUSH or RPUSH operation against one of the keys.
For first look. Your issue look like a trouble with blocking of connection.
There are two cases of what's happening.
First: Redis continues to block, even with a timeout. Weird but says so in the documentation. Thank you for showing me that.
Second: Assuming Redis blocks indefinitely, why does the test continue and not just wait right there? On my phone right now, so sorry for asking but are you blocking on the clients side or is Redis just returning (because of my timeout of 1) but still blocks the connection on the server side? But if that's the case, isn't that a bug?
EDIT: Additionally, any idea how to test this case or prevent it?
It does not look like a bug of Client or Redis, because the client has a test for BLPOP and it has a test for timeout too. Also, it was tested for all latest stable version of Redis: 2.6.17, 2.8.24, 3.0.7, 3.2.8, 4.0.8
But, I see that the RedisClient uses timeout' => 10
as config param in the test.
Also, you can try to check the behavior of Redis via redis-cli console
I'm back on my computer now and yeah I saw that too. Still, I'm calling
brpop($this-key, $timeout)
with
$timeout = 1
So shouldn't it return with null after a second?
See, this is the part I don't understand. I'm using the command as specified in the documentation.
EDIT: Also, your tests indicate the following:
$this->assertSame(null, $Redis->brpop(['list3', 'list4'], 1));
with a measured timeout of 1 <= timeout <= 2.5.
Which... is happening on my end too. (I can see phpunit pausing for a second) But null is not being returned. I'll test further and report all my results with their corresponding tests.
I hope I'm not totally misunderstanding something here. That'd be embarrasing :/
Try to use timeout = 10 for RedisClient, not for brpop command Example,
$Redis = ClientFactory::create([
'timeout' => 10,
]);
Okay this is promising. Using your suggestion (and the one used in your tests apparently)
public static function setUpBeforeClass()
{
self::$client = new RedisClient(['timeout' => 10]);
self::$client->flushdb();
}
results in a correct assertion in this test:
public function testLpopTimeout(): void
{
$list = new RedisList(self::$client, 'lpopTimeout');
self::assertNull($list->lpop(1));
}
Now the question is: Why is that? Is the default timeout so small that it simply closes the connection (and raises an EmptyResponseException)? And is there a way to "fix" this by simply raising the timeout when using a blocking command to the timeout set in the method?
The default timeout is 2 sec, and it is too much for real production or highload servers. Anyway, you can use the config to configure RedisClient as you need :)
I know I can use the config to change the client as needed but I ment a "on-the-fly" change. Something like
$client->config('timeout', 10);
Also, if the default is 2 seconds, why does 10 make it any better? You said yourself that 2 is too much. Using the blocking command with a max. timeout of 1 second should make no difference with a client timeout of 2 or 10 seconds? I'm just curious. I want this to be highly efficient. And setting the client to 10 seconds simply to fix something does not fix the issue itself but instead make things slower in the worst case.
So I'm writing a small library to wrap redis data types into PHP objects. Simple enough. But when testing the following:
and then immediately cleaning up the database by using
I get the following error and stack trace:
I can't figure out whats going on.
Oh and yeah the command doesn't even reach Redis (this is the last one before the exception):
Any idea what might be the problem here?
Using Redis 4.0.1 but not RedisClient4x0, because I want this to be compatible with as many versions as possible.
Thanks. K. Becker
EDIT: I played around a bit and noticed this behaviour only when using blocking methods. For example, if I use brpop and after that test some other methods like
lpop() does NOT pop 1 but instead null. Still figuring out why...