-
Notifications
You must be signed in to change notification settings - Fork 11k
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
[11.x] Cache::flexible
improvements
#52891
Conversation
$files = $this->mockFilesystem(); | ||
$hash = sha1('foobar'); | ||
$cache_dir = substr($hash, 0, 2).'/'.substr($hash, 2, 2); | ||
$files = new Filesystem; | ||
$store = new FileStore($files, __DIR__); | ||
$store->put('foobar', 'Hello Baby', 10); | ||
$files->expects($this->once())->method('exists')->with($this->equalTo(__DIR__.'/'.$cache_dir.'/'.$hash))->willReturn(true); | ||
$files->expects($this->once())->method('delete')->with($this->equalTo(__DIR__.'/'.$cache_dir.'/'.$hash)); | ||
|
||
$this->assertFileExists($store->path('foobar')); | ||
|
||
$store->forget('foobar'); | ||
|
||
$this->assertFileDoesNotExist($store->path('foobar')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm modified this test so it really does check that the file is cleaned up. There was an issue with the mock because of the new key being deleted. Mockery just burnt my time trying to make it work.
This test is 1000% better without the mocks anyway.
Cache::flexible
improvements
be64ca2
to
bfd90aa
Compare
@timacdonald Maybe it's just me, but I think this is still not working as expected when using Redis (I didn't test other drivers). When I do Although after re-creating the same cache item, it replaces the existing |
@Tklaversma, we have decided to leave the flexible keys to naturally expire for the cache drivers that respect a TTL. As you mentioned, they would be replaced correctly when called again, so functionally there is no issue, and otherwise they would naturally expire over time. This is similar to what happens with cache tags. It is not an ideal solution but the direction we are heading for now. We manually clean out the database and file drivers because they won't naturally expire over time. |
@timacdonald I understand, but can't there be a middle ground for In my particular case I don't want these remnants, because I have many cache items with high TTL's. I do have workarounds, but in the light of "keeping your database clean", having such an option to be able to delete those keys as well, would be great addition. And I don't think I'm the only one in this matter. I'm curious to your thought about this. Let me know 👍🏻 |
I don't think we have plans for this but will certainly keep an eye feedback around all this. |
@timacdonald Ok, readying a PR. I found out that you already did delete those |
See laravel#52891 Signed-off-by: Rood Fruit B.V <development@roodfruit.studio>
See #52936. |
This PR is actually breaking my CLI App when using In this line: There's actually no file named that. but it tries to delete it and the holy Mustn't there be an Exception (Full):
|
@mra-dev, do you have a custom implementation of the filesystem in your application? I can't seem to replicate that behaviour locally. I tried with the following in a fresh Laravel application. Cache::driver('file')->forget('key');
Cache::driver('file')->put('key', 'value', ttl: 5);
Cache::driver('file')->forget('key'); I've opened a PR with a passing test for this behaviour: #53018 Could you provide a way for me to replicate the issue to ensure we have an appropriate test and fix in place? |
@timacdonald I'm using pure Laravel (nothing custom) The problem is that i'm in CLI. Inside web side, everything's fine. |
Oh, and by the way, there are cases which may there be "race condition" or "concurrency" or in "Fibers". |
Thanks for the additional info. Can you see why my test in my PR would be passing without adding any changes? I've tried this on both the web and the CLI and everything is working as expected. Not seeing any logs or exceptions. // console.php
Artisan::command('dev', function () {
Cache::driver('file')->forget('key');
Cache::driver('file')->put('key', 'value', ttl: 5);
Cache::driver('file')->forget('key');
echo 'ok';
});
// web.php
Route::get('/', function () {
Cache::driver('file')->forget('key');
Cache::driver('file')->put('key', 'value', ttl: 5);
Cache::driver('file')->forget('key');
return 'ok';
}); Wondering if there is some We will get it fixed for you. Just want to make sure we have a test in place for future developers modifying the code. |
One potential thing could be write-protection that Laravel does on the file. One another weak possibility could be the Queue's long running process not knowing PHP's "clearstatcache" !!!? But, 100% sure that this line corrupts the APP. Maybe it isn't created at all in normal cache puts ??! (i mean the flexible cache file) |
And, yes. sorry for double message bug i have. |
They key thing i remembered to point out: |
I tried to replicate this in a similar situation. |
Can you please confirm in your application that the changes here fixes your problem with certainty? I have no way to confirm my fix even works so I'm shooting in the dark. |
@timacdonald I'm gonna check it right away. and shoot a video for it. |
✅ I'm confirming that this is the solution. P.S: I tested it by manually changing code in
|
BTW; @timacdonald Do you think using |
Are you modifying the files in That flag only applies only to the files it is within. |
@timacdonald |
@timacdonald Should I create an issue for this, or has it already been fixed? |
I'll fix this in #53018. Will have it opened today. |
Bugfix
Addresses a potential bug in
Cache::flexible
where the main key has been forgotten, viaCache::forget('foo')
, but the TTL key, i.e.,foo:created
, remains in the cache.When
Cache::flexible
is called again,null
is returned rather than calling theClosure $callback
and refreshing the value in the cache.There is a race condition in this solution where the
$value
is intentionallynull
and the value expires after we retrieve it from the cache but before we check$this->missing($key)
. I don't really see any real-world problem with refreshing the cache in that situation though. The value just expired after all. Heck, I'd even call it a feature.Cleanup flexible TTL keys
The database and file driver may leave behind TTL keys when the main key has been forgotten. Both the database and file driver will now attempt to cleanup the flexible TTL keys as well.
TTL key rename
Because we now implicitly clean up flexible TTL keys in the database and file driver, I felt it best we rename the TTL key, as
...:created
could easily be a user land key that we accidentally delete.We now namespace the key
illuminate:cache:flexible:created:{key}
.I suppose this is a breaking change, but I think removing the possibility of accidentally deleting user-land keys is more breaking than having the cache value refreshed early for this one off change.
Standardise key names
While I was in here making this change I also updated the defer key and the cache lock name to match the
illuminate:cache:flexible:*
pattern.fixes #52847