6

I am using laravel caching (the remember() method) on a website with a code like this:

$postedItems = Cache::remember('home_posted_items', $this->cacheTimes['postedItems'], function() {

    /* the stuff that prepares data */

    return ['items' => $items, 'firstItemNumber' => $firstItem];
});

The problem is that sometimes (every few days, I'd say) cached file seems to become corrupted and as a result I have downtime until the cache expires (unless I clear it manually).

Here is a part of the error stack that might be relevant:

[2017-02-04 22:01:34] production.ERROR: ErrorException: unserialize(): Error at offset 131059 of 131062 bytes in /home/path/to/app/vendor/laravel/framework/src/Illuminate/Cache/FileStore.php:78
Stack trace:
#0 [internal function]: Illuminate\Foundation\Bootstrap\HandleExceptions->handleError(8, 'unserialize(): ...', '/home/path/to/...', 78, Array)
#1 /home/path/to/app/vendor/laravel/framework/src/Illuminate/Cache/FileStore.php(78): unserialize('a:2:{s:7:"item...')
#2 /home/path/to/app/vendor/laravel/framework/src/Illuminate/Cache/FileStore.php(47): Illuminate\Cache\FileStore->getPayload('home_posted_ite...')
#3 /home/path/to/app/vendor/laravel/framework/src/Illuminate/Cache/Repository.php(98): Illuminate\Cache\FileStore->get('home_posted_ite...')
#4 /home/path/to/app/vendor/laravel/framework/src/Illuminate/Cache/Repository.php(202): Illuminate\Cache\Repository->get('home_posted_ite...')
#5 [internal function]: Illuminate\Cache\Repository->remember('home_posted_ite...', 1, Object(Closure))
#6 /home/path/to/app/vendor/laravel/framework/src/Illuminate/Cache/CacheManager.php(318): call_user_func_array(Array, Array)
#7 /home/path/to/app/bootstrap/cache/compiled.php(6089): Illuminate\Cache\CacheManager->__call('remember', Array)
#8 /home/path/to/app/app/Http/Controllers/HomeController.php(197): Illuminate\Support\Facades\Facade::__callStatic('remember', Array)

How to solve this problem?

From experience I know that clearing the cache solves the problem. So it seems that the issue is some corruption in files. I think if I could notice "the file is unreadable" and just clear the cache (Cache::forget(...)), it should solve the problem.

What would be the best way to notice such error? It seems that all the logic of retrieving the file is hidden inside the remember() method. Should I just unwrap it and use other methods, something like the following?

if (!($postedItems = @Cache::get('home_posted_items'))
{
    // prepare data

    $postedItems = ['items' => $items, 'firstItemNumber' => $firstItem];

    Cache::put('home_posted_items', $postedItems, $this->cacheTimes['postedItems']);
}
Džuris
  • 2,115
  • 3
  • 27
  • 55
  • I had a similar issue previously with laravel 4.2, at that time for some reason the files of the cache used to be deleted and then the caching class will try to get the cache and fails because the file is not readable (does not exist) and after cleaning the cache everything just works fine. what I want to say is that even if you use Cache::put instead of remember it will not change anything, the only way to over come this is to invalidate the cache once in a while when you know this is about to happen – Ahmad Hajjar Mar 03 '17 at 18:32
  • Have you a disk quota or are you running out of space perhaps? Or is there some unexpected char into string you are trying to unserialize? Best way to preceed imho is to VarDump the content at line 78 of FileStore.php. Let me know what you find. – DonCallisto Mar 04 '17 at 08:53
  • @DonCallisto there are no problems with the space, I am not running out of it. But it seems that the files however get cut for some reason. I catched an exception and wrote it to log file - it turns out it was cut off new the end. It's strange because it only happens sometimes and there seems to be no resource limitations reached. – Džuris Mar 05 '17 at 00:21
  • Issue like these, often, are about illegal chars serialize. Don't know what is written to cache, but this could be definitely the case – DonCallisto Mar 05 '17 at 07:48
  • @DonCallisto it can't be that because the content to be cached only changes once per day. The cache gets corrupted, I clear it, the same content is recached and it's fine. – Džuris Mar 05 '17 at 10:17
  • @DonCallisto I just noticed that it was cut in a middle of a key which I know for sure only consists of lowercase letters. – Džuris Mar 05 '17 at 13:27
  • Are you sure you are using file cache? What is your default value in "config/cache.php"? – Jannes Botis Mar 10 '17 at 13:39

2 Answers2

1

IMHO could be a problem with file driver. I think that if you have a good web server able to handle concurrent requests the problem is that the file driver is not so able at handle concurrency.

And that is related to the fact that usually filesystems itself are not so good at handling different concurrent processes reading/writing to same file.

In the end I advise you to switch the driver to something more capable at handling concurrency, i.e Memcached or Redis, but also Database should be good enough.

You can find the same suggestion for session here, look at the second post, and I think that could be relevant for cache file driver too.

dparoli
  • 8,891
  • 1
  • 30
  • 38
  • This is not a solution that I could put in place but I believe that you are pointing at the correct issues. I guess that's enough for the bount as there is nobody better here :) – Džuris Mar 10 '17 at 14:05
  • Thank you very much indeed @Džuris hope this answer can be helpful – dparoli Mar 10 '17 at 14:13
0

It does not seem a permission issue(you can see the #1 in stack trace), somehow laravel is overriding(corrupting) the cache files. You need to find out what content you have at the end of the file.

You also need to check what kind of content you are putting to cache, laravel uses file storage plugin which could have a bug.

And best way to debug that is here. https://stackoverflow.com/a/10152996/3305978

Community
  • 1
  • 1
anwerj
  • 2,386
  • 2
  • 17
  • 36