-
Notifications
You must be signed in to change notification settings - Fork 11.2k
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
Rate limiter no longer works when compression/serialization is enabled since v11.39.0 #54307
Comments
Thank you for reporting this issue! As Laravel is an open source project, we rely on the community to help us diagnose and fix issues as it is not possible to research and fix every issue reported to us via GitHub. If possible, please make a pull request fixing the issue you have described, along with corresponding tests. All pull requests are promptly reviewed by the Laravel team. Thank you! |
Hello, please be aware that compression/serialization never properly worked with the Cache component before this release. It seems like the rate limiter component works on top of the cache component. Theoretically for rate limiting it makes not much sense to do this serialization/compression overhead. Either use a connection that does not set those config values or let us properly fix the issue. I can have a look after work today if its not urgent. @JeppeKnockaert can you provide me the phpredis version you are using? If its below |
Nothing urgent. I agree there are other ways to solve the issue that might be better. For example, we could also make the increment/decrement operations compression/serialization aware instead. The main issue is that in a clean Laravel project, by setting serialization or compression, rate limiting just breaks. At the very least, it seems prudent to put a big warning in the docs about that so people know to use a different connection in that case. I'm just using the version included in the most recent Dockerfile published by Laravel Sail, that's Thanks for looking into it! |
I was able to reproduce it locally now. I also use phpredis For now I want to ensure that the Cache component works correctly. Inherently everything built on top of this component should also work correctly (e.g. rate limiter). If other components use redis with those settings enabled, they most likely are not working the same way as the Cache component has not been working since forever (e.g. Queue would need some adjustments next). But it makes no sense to fix those for now. Better to explicitly state in the docs that if those settings are set, that only Redis and Cache components support that. The others should use a normal connection. I will let you know what I find in the coming hours. Edit: Test code: $store = new RedisStore($this->redis[$driver]);
$repository = new Repository($store);
$rateLimiter = new RateLimiter($repository);
$this->assertFalse($rateLimiter->tooManyAttempts('key', 1));
$this->assertEquals(1, $rateLimiter->hit('key', 60));
$this->assertTrue($rateLimiter->tooManyAttempts('key', 1)); Working version where Serialization/Compression disabled, yields following output:
Failing version where serialization is set to
It seems like when we store a key with an integer value, redis fails to increment it afterwards, because it stored it serialized. It seems like there is a problem on |
I have talked with the maintainer and contributors of phpredis. It is a known edge case "bug", where you can not increment a variable that has been set with a serialized/compressed connection. As its kind of by design to not distinguish the use case of the application and just pack everything when enabled, we need to fix it here on framework side. Solution is basically similar to what is done here. Instead of globally skipping the pack call for any Cache component usage, we should do this only when used by the RateLimiter component. (for setting the initial counter value) |
Proposed solution fixes the issue. Regarding globally avoiding packing for numeric values, it won't be an issue. |
I just want to highlight the implications of this fix: Right now EVAL values won't be serialized/compressed when they are numbers. This potentially can cause the following bugs: Case 1:
Case 2:
In addition we still have this edge case that will cause the rate limiter to not work. If we get into this if condition, we will set a compressed/serialized value. Future increments won't work. I will open a second fix later today for this case (should actually never happen? maybe when connection fails on the increment above?), and also one a bit later that proposes a different approach without globally disabling the packing for numbers. The proposal involves to disable the options for this |
Good news, Will post here once I know more. |
Laravel Version
11.39.0
PHP Version
8.4.3
Database Driver & Version
No response
Description
When using Redis as a cache driver combined with compression or serialization, the rate limiter no longer works in the latest release: the increment method always returns 0.
This seems to be related to #54221
More specifically, it seems that adding a key and then incrementing that key is the thing that breaks the rate limiter
doing the above always returns 0.
That's because the incrby function in Redis only works on integers, not on serialized/compressed data.
I can try and submit a PR with a fix, but I'm not sure what the preferred way forward would be.
Steps To Reproduce
I created a test case here: JeppeKnockaert/laravel-cache-bug-report@e983654
To execute the tests:
The first test is the only that succeeds, because no compression or serialisation are configured.
The text was updated successfully, but these errors were encountered: