Answers:
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优化了缓存管理,并且不需要使缓存无效。
方法是与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核心功能做这个工作。
不,没有。并不是的。至少不在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_exit
,hook_watchdog
而这些hook_language_init
钩子并不想仅仅为了提供依赖缓存清除的功能而实现。
这里的大招:
尽管D8之前的版本不存在任何问题,但您可以基于标准后端编写自己的数据库后端DrupalDatabaseCache
,然后将任何或所有种类的逻辑写入clear()
函数中。快速浏览会发现这在D7中是相当简单的(只需将类复制到您的自定义名称,并通过module_invoke_all()
适当地添加以对其进行修改等),并且使用cache_backport模块甚至可以在D6中使用。然后,将要幻想化的所有缓存箱指向透明,然后就应该走了。
如果你看一下源drupal_flush_all_caches()
和clear_cache_all()
,你会看到,没有挂钩被调用后结算,这是一个非常错误无赖。
很难保证用户永远不必等待构建某些缓存条目,因此,我尽量避免完全清除缓存。
一种真正有用的方法是更改性能页面,以建立一个提交处理程序,该处理程序仅清除面向前的缓存,而不涉及菜单,注册表和类似的核心缓存。我在此方面取得了不错的结果,因为菜单和注册表的重建大约要花费一半的时间来重建整个缓存。
另一件事是我有一个drush脚本,它对drupal_http_request()
我所有的URL(不仅是重要的URL)都执行,以便所有内容都被缓存。如何完成此操作因站点而异。有时,我只能对已发布的节点进行EFQ,并以此方式构建URL。其他时候,您可以查询XML网站地图表以获取URL。然后,我可以根据需要经常从系统cron调用此命令。
几个选项:
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文件中进行设置,然后每当完成缓存清除后都应调用该挂钩。
这可能并不适合所有人,并且可能不适用于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
对所有并发用户可用),该挂钩可能会同时被触发多次,尤其是在您有大量用户的情况下。
我有一个类似的需求,即当客户单击“刷新所有缓存”按钮时,他们希望刷新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
}
您可能想尝试https://www.drupal.org/project/recacher-它使用“缓存过期”模块来检测过期的页面,然后使用出色的HTTPRL仅重新缓存那些页面。