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

16

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 cherche, c'est un moyen de savoir quand le cache vient d'être effacé , de préférence un hook, donc je peux lancer ce fonctions de génération.

Une idée ?

Gregory Kapustin
la source
Selon ce que vous essayez d'accomplir, la réponse de phayes en bas de la page est une bonne solution pour déclencher le code après la suppression des caches.
Lester Peabody

Réponses:

7

Il n'y en a pas dans Drupal 7.x mais cela a été ajouté en tant que hook principal, hook_rebuild dans Drupal 8.x après que suffisamment de personnes l' aient demandé. Il y a 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 a effacé le cache, n'est-ce pas? Une autre façon d'aborder cela serait d'utiliser Elysia cron qui a un certain nombre d'améliorations significatives au fonctionnement de cron mais deux qui pourraient être pertinentes pour votre cas d'utilisation sont:

Elysia Cron étend le cron standard Drupal, 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 chaque jour à 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 point d'ancrage à 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 d'effacement 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 vidage du cache spécifique dans Elysia cron pour qu'elle s'exécute à un rythme différent du reste de vos opérations cron. 6 heures, etc.

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

schnippy
la source
Eh bien, c'est une vraie déception. Dépêchez-vous D8! En fait, j'ai déjà, comme je vous l'ai dit, un cron avec elysia_cron, qui court toutes les minutes, réchauffant ce dont j'ai besoin. Mais comme mon site va avoir> 10.000 / visites / heure, je suis quasiment sûr que sbdy tombera sur des caches vides ... Thx en tout cas, je sais maintenant que c'est une limitation D7!
Gregory Kapustin
12

Pour ce faire, utilisez-le hook_flush_cachesen 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
}

L'utilisation register_shutdown_functionsignifie que notre fonction de reconstruction de cache sera appelée après l'effacement des caches. Nous abusons hook_flush_cachesd'une manière qui n'a jamais été destinée à être utilisée, mais cela devrait faire exactement ce dont vous avez besoin.

phayes
la source
J'aime vraiment cette solution. Avant de l'utiliser moi-même, j'ai recherché tous les problèmes / conflits connus à l'aide register_shutdown_function()de Drupal et suis tombé sur drupal_register_shutdown_function () : "Wrapper pour register_shutdown_function () qui intercepte les exceptions levées pour éviter" Exception levée sans cadre de pile dans Inconnu " . I Je sais que cela me fait du bien abusing hook_flush_cachessi j'utilise uniquement les fonctions de base de Drupal pour le faire.
runswithscissors
11

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 à nouveaudrupal_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 quoi que ce soit 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 appelle seulement hook_boot, hook_exit, hook_watchdoget hook_language_init- crochets que vous ne voulez pas mettre en œuvre que pour fournir des fonctionnalités en fonction de claire-cache.

Mołot
la source
Bon sang, il m'a fallu trop de temps pour ajouter tous ces liens;) Je vais le laisser pour l'instant car je ne peux pas me forcer à le supprimer, après tant de temps passé à expliquer pourquoi cela ne peut pas être fait.
Mołot
3
Laissez-le, c'est une bonne réponse.
mpdonadio
Oui laissez-le, je ne peux pas vérifier toutes les bonnes réponses mais je l'ai augmenté :)
Gregory Kapustin
8

Grands traits ici:

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

Jimajamma
la source
3
C'est probablement la meilleure solution, le seul «problème» étant que si vous avez plusieurs bacs de cache (memcache, redis, etc.), vous devez étendre plusieurs classes de cache. Ça vaut quand même le coup
Clive
Ne fonctionnerait pas avec le cache dans memcached, apc ou une autre solution non-db, n'est-ce pas?
Mołot
J'utilise Redis, je ne sais pas si cela fonctionnerait.
Gregory Kapustin
Si vous utilisez drupal.org/project/redis, vous devriez pouvoir simplement copier ou autrement modifier les classes fournies, etc. dans un module personnalisé, puis les utiliser à la place. Si, cependant, vous utilisez quelque chose sur le modèle de la plate-forme Panthéon où ils fournissent tout le gros du travail pour redis, alors oui, vous devrez vous coordonner avec eux à propos de tout cela.
Jimajamma
3

Si vous regardez la source de drupal_flush_all_caches()et clear_cache_all(), vous verrez qu'aucun hook n'est invoqué après la suppression, ce qui est un joli 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 la suppression complète 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.

mpdonadio
la source
1

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 effacement de cache vous permettant de modifier l'effacement drupal_alter('apdqc_cache_clear', $cid, $wildcard, $this->bin, $caller);et après vous avoir permis de réagir à l'effacement module_invoke_all('apdqc_cache_clear', $cid, $wildcard, $this->bin, $caller);. Faites fonctionner APDQC correctement et définissez-le $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é.

mikeytown2
la source
1

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.

A évidemment HOOKbesoin d'ê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_initn'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, les 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_setdevient disponible pour tous les utilisateurs simultanés - ce hook peut être déclenché plusieurs fois simultanément, surtout si vous avez un grand nombre d'utilisateurs.

Pebbl
la source
0

J'avais un besoin similaire, où un client voulait vider à la fois les caches Drupal et Varnish lorsqu'il appuyait 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
}
Travis Lilleberg
la source
Thx Travis, mais je cherche un moyen qui s'accroche à toute mise en cache claire, pas seulement celle déclenchée volontairement par un utilisateur.
Gregory Kapustin
0

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.

Vacilando
la source