web-dev-qa-db-fra.com

Existe-t-il un moyen d'accrocher la suppression du cache?

Pour un site Web de grande institution, avec des caches lourds, j'aimerais générer des caches dès que possible, afin qu'aucun utilisateur ne puisse arriver lors de la génération du cache ...

J'ai un cron défini toutes les minutes qui le fait, en exécutant quelques fonctions et en demandant des pages critiques, mais ce que je recherche est n moyen de savoir quand le cache vient d'être effacé, de préférence un crochet, donc je peux lancer cette génération de fonctions.

Une idée ?

16
Gregory Kapustin

Il n'y en a pas dans Drupal 7.x mais cela a été ajouté en tant que crochet principal, hook_rebuild dans Drupal 8.x après suffisamment de personnes l'ont demandé. Il existe peut-être un meilleur moyen de résoudre votre problème dans 7.x - vous essayez d'initier une sorte de fonctionnalité de réchauffement du cache juste après que cron vide le cache, n'est-ce pas? Une autre façon d'aborder cela serait à utiliser Elysia cron qui a un certain nombre d'améliorations importantes au fonctionnement de cron, mais deux qui pourraient être pertinentes pour votre cas d'utilisation sont:

Elysia Cron étend Drupal cron standard, permettant un contrôle fin du grain sur chaque tâche et plusieurs façons d'ajouter des tâches cron personnalisées à votre site.

  • Définissez les horaires et les fréquences de chaque tâche cron (vous pouvez exécuter certains travaux tous les jours à une heure spécifiée, d'autres uniquement mensuellement, etc.). Pour chaque tâche, vous pouvez simplement choisir entre certaines options fréquemment utilisées ("une fois par jour", "une fois par mois" ...), ou utiliser une puissante syntaxe de type "linux crontab" pour définir les horaires précis. Vous pouvez même définir vos options fréquemment utilisées pour accélérer la configuration du site. ...
  • Modifiez la priorité/l'ordre d'exécution des tâches. ...

Vous pouvez utiliser ce module pour avoir un meilleur contrôle sur la façon dont votre cron s'exécute pour aider à résoudre le problème de cache périmé. Plus précisément, vous pouvez ajouter un crochet à vos fonctions de reconstruction à cron, puis à l'aide d'Elysia cron, définissez ces opérations pour qu'elles s'exécutent immédiatement après l'opération de suppression du cache.

Il semble également que vous ayez des problèmes avec l'exécution de cron, ce qui conduit à une recréation trop fréquente du cache. Si tel est le cas, vous pouvez définir l'opération de suppression du cache spécifique dans Elysia cron pour qu'elle s'exécute à un rythme différent du reste de vos opérations cron, par exemple, l'indexation de la recherche se mettra à jour toutes les 5 minutes mais la suppression complète du cache ne s'exécutera que toutes les 6 heures, etc.

Affiner la gestion du cache cron: drupal cron invalidera le cache variable à chaque exécution de cron, et ceci est un gros problème de performances si vous avez une tâche fréquemment appelée. Elysia cron optimise la gestion du cache, et ne le fait pas besoin d'invalider le cache.

7
schnippy

Pour ce faire, utilisez hook_flush_caches en combinaison avec register_shutdown_function. Exemple de code:

/**
 * 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
}

En utilisant register_shutdown_function signifie que notre fonction de reconstruction de cache sera appelée après les caches ont été effacés. Nous abusons hook_flush_caches d'une manière qui n'a jamais été conçue pour être utilisée, mais cela devrait faire exactement ce dont vous avez besoin.

12
phayes

Non, il n'y en a pas. Pas vraiment. Du moins pas dans 6 ou 7. En supposant 7:

Si vous regardez drupal_flush_all_caches() vous verrez qu'il invoque hook_flush_caches() . Ce crochet est destiné à:

"ajouter des noms de table de cache à la liste des tables de cache qui seront effacées par le bouton Effacer de la page Performances ou chaque fois que drupal_flush_all_caches est invoqué."

Il serait tentant de simplement faire durer le hook de votre module et d'y écrire du code. Mais regardons à nouveau drupal_flush_all_caches() . La suppression réelle se produit comme ceci:

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

Cela signifie que tous les crochets sont tirés avant que tout ne soit vraiment effacé. Il n'y a qu'une seule fonction appelée après la suppression réelle, _system_update_bootstrap_status() , mais elle n'appelle que hook_boot , hook_exit , hook_watchdog et hook_language_init - crochets que vous ne voulez pas implémenter uniquement pour fournir un cache-clear- fonctionnalité dépendante.

11
Mołot

Grands traits ici:

Bien qu'il n'y ait pas de hook en pré-D8, vous pouvez écrire votre propre backend de base de données basé sur le standard DrupalDatabaseCache puis écrire une ou toutes sortes de logique dans votre clear() une fonction. Un coup d'œil rapide suggérerait que ce soit assez simple dans D7 (copiez simplement la classe dans votre nom personnalisé et modifiez-le, etc. en lançant une module_invoke_all() selon le cas) et avec le module cache_backport fonctionnerait même en D6. Pointez ensuite tous les bacs de cache que vous souhaitez imaginer sur clair et vous devriez être sur votre chemin.

8
Jimajamma

Si vous regardez la source pour drupal_flush_all_caches() et clear_cache_all() , vous verrez qu'aucun crochet n'est invoqué après le nettoyage, ce qui est un joli bug bug.

Il est très difficile de garantir qu'un utilisateur n'aura jamais à attendre la création de certaines entrées de cache, j'essaie donc d'éviter autant que possible l'effacement complet du cache.

Une méthode qui aide vraiment est de modifier la page de performances pour câbler un gestionnaire de soumission qui efface simplement les caches orientés vers l'avant et ne touche pas les menus, le registre et les caches de base similaires. J'ai obtenu de bons résultats avec cela, car la reconstruction du menu et du registre prend environ la moitié du temps pour une reconstruction complète du cache.

L'autre chose que j'ai un script drush qui fait un drupal_http_request() sur toutes mes URL (pas seulement les plus importantes) pour que tout soit mis en cache. La manière de procéder varie selon le site. Parfois, je peux simplement EFQ les nœuds publiés et créer des URL de cette façon. D'autres fois, vous pouvez interroger les tables de sitemap XML pour obtenir votre URL. J'appelle ensuite cela depuis mon système cron aussi souvent que nécessaire.

3
mpdonadio

Quelques options:
https://www.drupal.org/project/cache_graceful pourrait être exactement ce que vous voulez.

https://www.drupal.org/project/apdqc a 2 crochets qui se déclenchent sur un cache clear vous permettant de modifier le clear drupal_alter('apdqc_cache_clear', $cid, $wildcard, $this->bin, $caller); et après vous avoir permis de réagir au effacer module_invoke_all('apdqc_cache_clear', $cid, $wildcard, $this->bin, $caller);. Assurez-vous que APDQC fonctionne correctement et définissez $conf['apdqc_call_hook_on_clear'] = TRUE; dans votre fichier settings.php, puis les hooks doivent être appelés chaque fois qu'un effacement du cache est effectué.

1
mikeytown2

Cela peut ne pas convenir à tout le monde et peut ne pas être assez rapide pour l'OP - car il n'est déclenché qu'à l'initialisation de la page suivante. Cependant, cela m'a aidé à déclencher du code juste après un "cache effacer tout" qui n'était pas sensible au temps.

De toute évidence, HOOK doit être remplacé par votre propre nom de module.

/**
 * 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.
}

Si vous avez un bac spécifique que vous devez cibler, ce qui précède peut être modifié pour le prendre en charge, tant que le bac entier est vidé au moment où votre cache est vide.

hook_init n'est exécuté que pour les pages non mises en cache. Bien qu'une suppression complète du cache ne signifie pas de pages mises en cache, cela ne devrait pas poser de problème. Cependant, des systèmes de mise en cache externes comme Varnish entraveront ce déclenchement, et signifieront que cela ne se produira que lorsque la prochaine demande appropriée reviendra à Drupal.

Il convient également de noter qu'en fonction de votre système de mise en cache - exactement quand un cache_set devient disponible pour tous les utilisateurs simultanés - ce crochet peut être déclenché plusieurs fois simultanément, surtout si vous avez un grand nombre d'utilisateurs.

1
Pebbl

Vous voudrez peut-être essayer https://www.drupal.org/project/recacher - il utilise le module d'expiration du cache pour détecter les pages expirées, puis re-cache uniquement ces pages en utilisant l'excellent HTTPRL.

0
Vacilando

J'avais un besoin similaire, où un client voulait vider les caches Drupal et Varnish quand ils appuyaient sur le bouton "Vider tous les caches". J'ai détourné cet élément de menu pour le faire.

Cela n'atteindra aucun effacement du cache sur cron ou ailleurs - juste sur le lien du menu.

/**
 * 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
}
0
Travis Lilleberg