有没有办法挂钩缓存清除?


16

对于拥有大量高速缓存的大型机构网站,我想尽快生成高速缓存,以便没有用户可以到达高速缓存生成...

我通过执行一些功能并请求关键页面来设置所有时间的cron,但是我想寻找的是一种知道何时刚刚清除缓存(最好是钩子)的方法,因此我可以启动它生成功能。

任何想法 ?


根据您要完成的工作,在页面下找到phayes的答案是一个不错的解决方案,可以在清除缓存后触发代码。
Lester Peabody

Answers:


7

Drupal 7.x中没有此功能,在足够多的人请求后,它已作为核心钩子添加到Drupal 8.x中的hook_rebuild中。不过,在7.x中可能有更好的方法来解决问题-您正试图在cron清除缓存后立即启动某种缓存预热功能,对吗?解决此问题的另一种方法是使用Elysia cron,它对cron的运行方式有许多重大改进,但可能与您的用例有关的有两个:

Elysia Cron扩展了Drupal标准cron,允许对每个任务进行精细控制,并提供了几种向您的站点添加自定义cron作业的方法。

  • 设置每个cron任务的时间和频率(您可以每天在指定的时间运行一些作业,而其他每个月只能运行一次,依此类推)。对于每个任务,您只需在一些经常使用的选项(“一天一次”,“一个月一次” ...)之间进行选择,或者使用功能强大的类似“ linux crontab”的语法来设置准确的时间。您甚至可以定义常用选项来加快站点配置。...
  • 更改任务执行的优先级/顺序。...

您可以使用此模块更好地控制cron的运行方式,以帮助解决过时的缓存问题。具体来说,您可以向cron的重建函数添加一个挂钩,然后使用Elysia cron将这些操作设置为在清除缓存操作后立即运行。

听起来还好像您可能会遇到cron运行问题,从而导致频繁重新创建缓存。在这种情况下,您可以将Elysia cron中的特定缓存清除操作设置为与其余cron操作不同的运行速度,例如,搜索索引将每5分钟更新一次,但完整的缓存清除将仅在每5分钟运行一次6小时等

微调cron缓存管理:drupal cron将在每次cron运行时使变量缓存无效,如果您有一个经常调用的任务,这将是一个很大的性能问题。Elysia cron优化了缓存管理,并且不需要使缓存无效。


好吧,这真是个无赖。快点D8!实际上,正如我告诉您的那样,我已经有了一个带有elysia_cron的cron,它每分钟运行一次,从而温暖了我所需要的。但是,由于我的网站的访问量将超过10.000 /小时/小时,因此我很确定sbdy会落在空的缓存上...不管怎样,我知道这是D7的限制!
Gregory Kapustin 2013年

12

方法是与hook_flush_caches结合使用register_shutdown_function。示例代码:

/**
 * Implements hook_flush_caches().
 */
function mymodule_flush_caches() {
   // After caches are cleared we will run mymodule_cache_rebuild()
   register_shutdown_function('mymodule_cache_rebuild');

   // We don't want to add any custom cache-tables, so just return an empty array
   return array();
}

/**
 * Rebuild expensive cache items that need to be rebuilt immediately.
 */
function mymodule_cache_rebuild() {
  // Do the cache rebuild work here
}

使用register_shutdown_function的手段,我们的缓存重建函数将被调用缓存已被清除。我们正在滥用hook_flush_caches它从未被使用过的方式,但这应该完全满足您的需求。


我真的很喜欢这个解决方案。在我自己使用它之前,我搜索了register_shutdown_function()在Drupal中使用的任何已知问题/冲突,并遇到了Drupal核心的drupal_register_shutdown_function()“ register_shutdown_function()的包装可以捕获抛出的异常,以避免“在Unknown中没有堆栈帧的情况下抛出的异常”。知道这让感觉更好abusing hook_flush_caches,如果我只使用Drupal核心功能做这个工作。
runswithscissors

11

不,没有。并不是的。至少不在6或7中。假设7:

如果您看一下,drupal_flush_all_caches()就会看到它调用hook_flush_caches()。该钩子旨在:

“将缓存表名称添加到将在“性能”页面上的“清除”按钮或每当调用drupal_flush_all_caches时将清除的缓存表列表。”

将模块的钩子放在最后并在其中编写代码将很诱人。但是,让我们再看一看drupal_flush_all_caches()。实际删除是这样的:

  $cache_tables = array_merge(module_invoke_all('flush_caches'), $core);
  foreach ($cache_tables as $table) {
    cache_clear_all('*', $table, TRUE);
  }

这意味着在真正清除任何内容之前,所有的钩子都会被触发。在实际删除之后,只有一个函数被调用_system_update_bootstrap_status(),但它仅调用hook_boot,和-钩子hook_exithook_watchdog而这些hook_language_init钩子并不想仅仅为了提供依赖缓存清除的功能而实现。


该死,我花了很长时间才添加所有这些链接;)由于花了很多时间解释为什么无法完成,所以我暂时不能将其删除,因此请暂时将其保留。
Mołot

3
离开它,这是一个很好的答案。
mpdonadio

是的,离开它,我无法检查所有好的答案,但我调高了:)
Gregory Kapustin 2013年

8

这里的大招:

尽管D8之前的版本不存在任何问题,但您可以基于标准后端编写自己的数据库后端DrupalDatabaseCache,然后将任何或所有种类的逻辑写入clear()函数中。快速浏览会发现这在D7中是相当简单的(只需将类复制到您的自定义名称,并通过module_invoke_all()适当地添加以对其进行修改等),并且使用cache_backport模块甚至可以在D6中使用。然后,将要幻想化的所有缓存箱指向透明,然后就应该走了。


3
这可能是最好的解决方案,唯一的“问题”是,如果您有多个缓存容器(memcache,redis等),则必须扩展多个缓存类。仍然值得
克莱夫(Clive)

无法在memcached,APC或其他非数据库解决方案中使用缓存,对吗?
Mołot

我使用Redis,不确定是否可以使用。
格雷戈里·卡普斯汀

如果您使用的是drupal.org/project/redis,则应该能够在自定义模块中复制或修改提供的类等,然后改用它们。但是,如果您沿Pantheon平台使用某些东西,它们为Redis提供了所有繁重的工作,那么是的,您需要在所有这些方面与他们协调。
Jimajamma 2013年

3

如果你看一下源drupal_flush_all_caches()clear_cache_all(),你会看到,没有挂钩被调用后结算,这是一个非常错误无赖。

很难保证用户永远不必等待构建某些缓存条目,因此,我尽量避免完全清除缓存。

一种真正有用的方法是更改​​性能页面,以建立一个提交处理程序,该处理程序仅清除面向前的缓存,而不涉及菜单,注册表和类似的核心缓存。我在此方面取得了不错的结果,因为菜单和注册表的重建大约要花费一半的时间来重建整个缓存。

另一件事是我有一个drush脚本,它对drupal_http_request()我所有的URL(不仅是重要的URL)都执行,以便所有内容都被缓存。如何完成此操作因站点而异。有时,我只能对已发布的节点进行EFQ,并以此方式构建URL。其他时候,您可以查询XML网站地图表以获取URL。然后,我可以根据需要经常从系统cron调用此命令。


1

几个选项:
https : //www.drupal.org/project/cache_graceful可能正是您想要的。

https://www.drupal.org/project/apdqc有2个在缓存清除上触发的钩子,允许您更改清除,drupal_alter('apdqc_cache_clear', $cid, $wildcard, $this->bin, $caller);并在对清除作出反应之后module_invoke_all('apdqc_cache_clear', $cid, $wildcard, $this->bin, $caller);。让APDQC正常工作并$conf['apdqc_call_hook_on_clear'] = TRUE;在您的settings.php文件中进行设置,然后每当完成缓存清除后都应调用该挂钩。


1

这可能并不适合所有人,并且可能不适用于OP,因为它仅在下一页初始化时触发。但是,它帮助我在对时间不敏感的“缓存清除全部”之后触发代码。

显然HOOK需要替换为您自己的模块名称。

/**
 * Implements hook_init().
 */
function HOOK_init(){
  // if there is no cache_not_empty defined, define it 
  // and then trigger our cache cleared code
  if ( !cache_get('HOOK_cache_not_empty') ) {
    cache_set('HOOK_cache_not_empty', TRUE);
    foreach (module_implements('cache_cleared') as $module) {
      module_invoke($module, 'cache_cleared');
    }
  }
}

/**
 * Implements hook_cache_cleared().
 */
function HOOK_cache_cleared(){
  // do what you need here, in which ever module.
}

如果您有一个特定的垃圾箱需要定位,则可以对上述内容进行修改以支持它,只要在清除缓存时清空整个垃圾箱即可。

hook_init仅对非缓存页面执行。尽管由于完全清除缓存应该意味着没有缓存的页面,但这不会引起问题。但是,像Varnish这样的外部缓存系统会阻碍此触发,这意味着只有在下一个适当的请求返回到Drupal时才会发生。

还应注意的是,取决于您的缓存系统(确切地说,a cache_set对所有并发用户可用),该挂钩可能会同时被触发多次,尤其是在您有大量用户的情况下。


0

我有一个类似的需求,即当客户单击“刷新所有缓存”按钮时,他们希望刷新Drupal和Varnish缓存。我劫持了该菜单项。

这不会在cron或其他任何地方击中任何缓存清除-只是在菜单链接上。

/**
 * Implements hook_menu_alter().
 */
function mymodule_menu_alter(&$items) {
  if (isset($items['admin_menu/flush-cache'])) {
    $items['admin_menu/flush-cache']['page callback'] =
      "_mymodule_custom_flush_cache";
  }
}

/**
 * Hijacks the "flush all caches" button in menu
 */
function _mymodule_custom_flush_cache() {
  /**
   * Clear varnish, or other logic here
   */
  admin_menu_flush_cache(); //Run the normal cache clearing stuff
}

特雷维斯(Thx Travis),但我正在寻找一种挂钩任何清晰缓存的方式,而不仅仅是用户自愿触发的方式。
格雷戈里·卡普斯汀

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.