2014-07-13 62 views
0

我需要从外部API缓存返回的数据,听起来简单,但...Laravel缓存永远与*可能*到期

我想和到期日来缓存数据。我不希望缓存在该日期过期,我想尝试重新请求数据,如果成功,请覆盖旧数据。如果重新请求不成功,它应该只保留旧数据。

基本上,我需要Cache::forever();带有失效日期或一些自定义代码。

回答

3

您可以轻松地添加自己的方法作为宏:

Cache::macro('untilUpdated', function ($key, $date, Closure $callback) 
{ 
    if (! $date instanceof DateTime) 
    { 
     $date = Carbon::now()->addMinutes($date); 
    } 

    if (is_null($value = Cache::get($key))) 
    { 
     $data = $callback(); 

     Cache::forever($key, compact('date', 'data')); 

     return $data; 
    } 

    if ($value['date'] >= $date && ($data = $callback()) !== false) 
    { 
     Cache::forever($key, compact('date', 'data')); 

     return $data; 
    } 

    return $value['data']; 
}); 

然后,只需使用它的代码是这样的:

$value = Cache::untilUpdated('key', 10, function() 
{ 
    return API::call() ?: false; 
}); 
+0

这看起来相当真棒。我在哪里粘贴这个代码(宏本身)? – atwright147

+0

@ atwright147 - 任何你想要的。在你的'start/global.php','routes.php'中,或者在你的路径文件旁边创建一个'macros.php'文件,并将其包含在过滤器文件后面的'start/global.php'末尾。 –

+0

这太棒了!我已更正原始帖子中的一个小回复错误。另外,我一直在调用我的'untilUpdated()' – atwright147

2

这是一个非常有用的模式,但并不是许多缓存支持的模式,大多数缓存将在到期日期后过期(删除)高速缓存条目。

实现你自己很简单,你需要做的就是添加一个到期日期字段到你的API响应对象中,填充它,存储响应Cache::forever()。当您从缓存中检索响应时,请检查到期日期以及是否通过,尝试加载并缓存新数据,或者后退以返回陈旧副本。

您可能需要在响应中添加另一个字段 - 上次尝试刷新它的日期。然后,您可以使用它在新尝试新数据之间等待一段时间,如果API没有响应,这很方便。否则,在到期之后每次调用缓存数据都会浪费时间进行API调用。

您可以选择更复杂的图案,创建自己的新外观,该外观包装Laravel的Cache外观,并提供类似的方法。特别是,您可以编写自己的rememberForever方法的实现,以便在每次调用缓存时,都会传递一个函数,以便在响应丢失或失效时发出API请求。由于我不知道你的API查询是如何产生的,所以我无法提供这样的示例,但无论如何,第一种选择可能更简单!

1

将您的下一个更新日期存储在任何你喜欢的地方,只需使用简单的方法更新Cache::forever('your_key')的内容来检查新数据。

function checkForUpdates() 
{ 
    $date = time(); 

    if (Cache::has('my_key')) 
    { 
     if ($date >= $date_from_db) 
     { 
      $data = $this->getUpdatedData(); 

      if ($data !== Cache::get('my_key')) 
      { 
       Cache::forever('my_key', $data) 
      } 
     } 
    } 
    else 
    { 
     Cache::forever('my_key', $this->getData()); 

     MyDateModel::insert(['next_update' => date('d-m-Y H:i:s', strtotime('+1 week'))]); 
    } 
}