2010-09-17 4 views
2

Quelle est la meilleure façon de mettre en cache un jeu de résultats paginé avec rails et memcached?pagination et memcached dans les rails

Par exemple, messages contrôleur:

def index 
    @posts = Rails.cache.fetch('all_posts') do 
    Post.paginate(:conditions => ['xx = ?', yy], :include => [:author], :page => params[:page], :order => 'created_at DESC') 
    end 
end 

Cela ne fonctionne évidemment pas lorsque les params[:page] changements. Je peux changer la clé pour "all_posts_#{params[:page]}_#{params[:order]_#{last_record.created_at.to_i}", mais alors il pourrait y avoir plusieurs ordres possibles (récents, populaires, les plus votés etc) et il y aura une combinaison de pages et de commandes ... beaucoup de clés de cette façon.

Problème n ° 2 - Il semble que lorsque j'implémente cette solution, les caches sont écrits correctement et la page se charge correctement lors du premier appel à une action paginée. Lorsque je clique sur la même page, c'est-à-dire page1, avec l'ordre recent, il semble que le navigateur ne fait même pas un appel au serveur. Je ne vois aucune action de contrôleur appelée dans le journal de production. J'utilise passager, REE, memcached et rails 2.3.5. Firebug ne montre aucune demande en cours ....

Existe-t-il un moyen simple/plus gracieux de gérer cela?

Répondre

0

En ce qui concerne la mise en cache, il n'y a pas de solution facile. Vous pouvez mettre en cache chaque variante du résultat, et c'est ok si vous implémentez l'expiration automatique des entrées. Vous ne pouvez pas simplement utiliser all_posts, car de cette façon, vous devrez expirer des dizaines de clés si les posts sont modifiés.

Chaque instance de modèle AR a la clé .cache basée sur la méthode updated_at, qui est préférable, utilisez-la au lieu du dernier enregistrement. Ne basez pas non plus votre clé sur le dernier enregistrement, car si un message au milieu est supprimé, votre clé ne changera pas. Vous pouvez utiliser une logique comme celle-ci à la place.

class ActiveRecord::Base   
    def self.newest 
    order("updated_at DESC").first 
    end  
    def self.cache_key 
    newest.nil? ? "0:0" : "#{newest.cache_key}:#{count}" 
    end 
end 

Maintenant, vous pouvez utiliser Post.cache_key, qui se changer si un poste va se changer/supprimé ou créé.

En général, je voudrais simplement mettre en cache Post.all et paginer sur cet objet. Vous avez vraiment besoin de faire un profil pour trouver des goulots de bouteille dans votre application. En outre, si vous souhaitez mettre en cache toutes les variantes, effectuez plutôt la mise en cache des fragments/pages à la place.

Si c'est à vous de décider comment et où mettre en cache. Pas de sens unique ici. En ce qui concerne la deuxième partie de la question, il y a peu d'indices pour que je puisse trouver une réponse. Vérifiez si le navigateur effectue un appel sur tous les LiveHTTPHeaders, tcpdump, etc.

+0

Merci. Pour le deuxième problème, je pense que cette autre question pourrait vous donner plus d'indices. http://stackoverflow.com/questions/3743268/max-age-with-nginx-passenger-memcached-rails2-3-5. pour une raison quelconque, le max-age est réglé même si je ne fais rien dans mon application rails, essayant toujours de comprendre le problème. J'entends nginx est un proxy inverse aussi, peut-être qu'il a quelque chose à voir avec ça? – badnaam

+0

avec cette commande "(" updated_at DESC "). First" approche, cette requête va-t-elle s'exécuter chaque fois qu'une requête arrive? – badnaam

+0

Oui, il fonctionnera à chaque fois, sauf si vous combinez cela avec une autre approche de mise en cache. Mais en général, il n'y a pas d'autre moyen de le faire. Vous devez vérifier si le cache est valide en regardant dans votre base de données. Mais dans la plupart des cas, cela accélère beaucoup les choses de toute façon. – mdrozdziel