I'm having an odd problem using memcached with FuelPHP's Cache (using FuelPHP 1.4). For some reason, the expiration time seems to be out of sync by about 150 seconds. ie. I need to set expiration time to [number of seconds required] + 150. (So, for example, setting expiration to 160 would give me ~10s before the cache expires). Any value less than 150 isn't cached.
I thought this might be a server date/time problem, but I've just tried using PHP's Memcached extension to directly set values (bypassing FuelPHP's Cache), and I've found that expiration times work exactly as expected (ie. 10 = 10s; 160 = 160s). So it seems like it must be something in the Cache class.
Can anyone shed any light on this? I don't really want to have to write a custom Cache class just to get around this, but I do need to be able to accurately set expiration times.
Thanks.
function microtime_float()which in your case won't cache at all (since it only caches for 10 seconds), but the response is:
{
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
\Cache::set('test', 'value', 10);
$time_start = microtime_float();
while(true)
{
try
{
$var = \Cache::get('test');
}
catch (\Exception #e)
{
$time_end = microtime_float();
$time = $time_end - $time_start;
echo "Cache expired in $time seconds\n";
exit;
}
}
Thanks for that. Hmm, this is odd. I tried your code, and if I set the expiry time to, say, 170 I get:
Cache expired in 7.133584022522 seconds
Anything less than about 160 and cache expires in ~0.002 seconds (ie. immediately). This seems to be a problem with Memcached only: when I switch the Cache driver to "file" it works as expected (eg. 10 => ~10s)
One thing that occurred to me: I ran "date" on the server, and it looks like the system clock is about 2 mins 15 seconds behind UTC, which I'm guessing could well have something to do with this problem (though it's odd that the difference doesn't seem to match that ~160s offset)
However, as I said, when I call PHP's Memcached::set directly the expiry times work exactly as expected. It's as if Memcached is using relative/local times to expire, while FuelPHP's Cache is somehow locked to UTC. Could that make sense? (I had a quick look through Cache_Storage_Memcached, and I couldn't figure out where/why/how this would be happening) The fact that Memcached::set works fine does make me think that although the problem could be something to do with my local configuration, it must be specific to FuelPHP because I only see it when I access Memcached through FuelPHP's Cache.
Yes, it does seem odd...
The thing is though that (a) I ran the exact same code (ie. your test function above) with driver set to "memcached", "file", and "apc" and the problem only occurs when the driver is set to memcached (ie. with the "file" and "apc" drivers it expired in just over 10s; with "memcached" it expired in 0.002s); (b) like I said, this problem only occurs when I use FuelPHP's Cache: when I use Memcached::set($key, $value, 10) to cache something directly, the memcached value expires at the expected time (ie. after 10s).
Given (a) and (b), I'm finding it hard to imagine where the problem could be other than in FuelPHP's Memcached driver, though of course that could be a failure of imagination on my part!
I've actually got round the problem for now (I wrote my own simple cache class), so I'm no longer in urgent need of a solution, but do let me know if there's anything else you can think of that I can usefully test.
For what it's worth, my code is running in PHP 5.4 on an Amazon EC2 instance, using an Amazon Elasticache node as the Memcached client.
Ok, I dumped the contents of $payload (returned by memcached->get()) after line 264, and it's false, which is causing a "Cache has bad formatting" exception (cf. line 212).
$key looks fine though, so I went to the _set() method, and it turns out that if I try dumping the contents of $this->memcached->get($key) after it is set at line 242 (ie. just before "$this->_update_index($key);"), I still get "false". If I dump $this->memcached->getAllKeys() at this same point then I get an array of keys which includes $key so it seems like it's setting the value ok, but is then unable to retrieve it. I'm struggling to imagine why that would be.
Hope that's of some use. Let me know if there's anything else you'd like me to try!
Thanks for that. That clears up what's happening: there must be a discrepancy between the clock on my server and the server running memcached.
While I could and should (and perhaps even will!) fix that by correcting the clocks, it occurred to me that there is perhaps another solution, which could make the memcached driver more robust: to use the relative time (eg. 30s) when the expiration time is less than 30 days, and only use a unix timestamp when it's greater (in line with how the Memcached PHP extension handles expiration times). This would mean that even where server clock was innacurate, the inaccuracy would only affect caches where expiration time > 30 days (and unless the clock is completely wrong, the inaccuracy would most likely be less significant at these timescales anyway). This should make the Cache behave as expected even where the clock on the server running FuelPHP doesn't quite match the clock on the server running Memcached.
I tweaked the memcached storage driver to try the above, and it now seems to work as expected (eg. 10 --> ~10s, even on my server). In case you're interested, I've sent a pull request on Github with the updated version for you to take a look at. Hope it's of use! Do give me a shout if you have any thoughts / questions.
It looks like you're new here. If you want to get involved, click one of these buttons!