我有一个相当大的Rails应用程序,它在单独的服务器上使用memcached作为其缓存存储。
问题是我在似乎的生产环境中随机出现错误,表明memcached正在返回一个不正确的对象。
示例:
在此示例中,current_site
是一个帮助方法,它访问Site
模型上使用Rails.cache缓存模型的方法
ActionView::TemplateError in ListingsController#edit
undefined method `settings' for #<String:0xb565f8a0>
On line #12 of app/views/layouts/site.html.erb
9: <meta name="robots" content="noodp, all" />
10: <meta name="distribution" content="Global" />
11:
12: <% unless current_site.settings[:google_webmaster_verification_code].blank? %>
13: <meta name="verify-v1" content="<%= current_site.settings[:google_webmaster_verification_code] %>" />
14: <% end %>
15:
与......相比。
ActionView::TemplateError in ApplicationController#not_found
undefined method `settings' for #<Category:0xd5c6c34>
On line #12 of app/views/layouts/site.html.erb
9: <meta name="robots" content="noodp, all" />
10: <meta name="distribution" content="Global" />
11:
12: <% unless current_site.settings[:google_webmaster_verification_code].blank? %>
13: <meta name="verify-v1" content="<%= current_site.settings[:google_webmaster_verification_code] %>" />
14: <% end %>
15:
两者都应该返回Site
模型!
缓存的另一个例子表现奇怪:
ActionView::TemplateError in AccountsController#show
can't convert Category into String
On line #141 of app/views/layouts/site.html.erb
138: <li<%= class="first" if i == 0 %>><%= link_to top_level_category.title, top_level_category.path %></li><% end %>
139: </ul>
140: <% end %>
141: <% cache bottom_pages do %>
142: <ul><% Page.top_level.active.show_in_navigation.find(:all, :include => :slugs).each_with_index do |top_level_page, i| %>
143: <li<%= class="first" if i == 0 %>><%= link_to top_level_page.title, top_level_page.path %></li><% end %>
144: </ul>
以前有没有人遇到这样的事情?任何人都有想法诊断这个无法解释的问题!?我已经尝试切换出memcached客户端宝石,想想也许这是一个奇怪的错误,但这没有任何影响!感谢。
答案 0 :(得分:10)
这是由Passenger共享其与Memcached服务器的连接引起的。检查http://www.modrails.com/documentation/Users%20guide.html#_example_1_memcached_connection_sharing_harmful。
修复只是将Passenger的Rails生成更改为conservative
。
答案 1 :(得分:1)
可能会有所帮助的一些事情:
current_site
,以确切了解要返回的内容。memcached-tool host:port dump > /tmp/keys
查看memcache中的实际内容。答案 2 :(得分:1)
我也遇到了这个问题,并且解决了在缓存提供程序进行解组操作之前为每个类/模型添加require_dependency。也许在生产环境中这不是必需的,因为选项:config.cache_class设置为true,但在测试和开发中它是错误的。
实际上,Memcache(我正在使用的缓存提供程序)找不到引用的类来执行unmarshal,然后引发此错误。
在这篇文章中有一个更好的解决方案来解决这个问题: http://kballcodes.com/2009/09/05/rails-memcached-a-better-solution-to-the-undefined-classmodule-problem/
问候!
答案 3 :(得分:0)
是的,我已经发生了这种情况。对我来说,这是因为我正在做Rails.cache.fetch(key)
并且密钥是空白的。
我已经在Rails控制台中完成了一些操作,并使用以下内容:
Rails.cache.read validkey # Get back the proper data
Rails.cache.fetch('') { 'abc' } # Error in rails log: 'MemCacheError ():'
Rails.cache.read validkey # Get back nil
Rails.cache.read validkey # May get back proper data
答案 4 :(得分:0)
在此处添加评论以防其他人出现... kballcodes.com网址不再有效(尽管您仍然可以通过archive.org访问它)。在该博客文章的评论中,有人描述了一种方法,使Marshal尝试加载有问题的对象,如果它首先抛出'undefined class / module'错误。我在下面包含了该代码,并在代码示例下引用了原作者。
将其添加到RAILS_ROOT / config / initializers /文件夹中的初始化文件中:
#
# Marshal.load is a C-method built into Ruby; because it's so low-level, it
# bypasses the full classloading chain in Ruby, in particular the #const_missing
# hook that Rails uses to auto-load classes as they're referenced. This monkey
# patch catches the generated exceptions, parses the message to determine the
# offending constant name, loads the constant, and tries again.
#
# This solution is adapted from here:
# http://kballcodes.com/2009/09/05/rails-memcached-a-better-solution-to-the-undefined-classmodule-problem/
#
class <<Marshal
def load_with_rails_classloader(*args)
begin
load_without_rails_classloader(*args)
rescue ArgumentError, NameError => e
if e.message =~ %r(undefined class/module)
const = e.message.split(' ').last
const.constantize
retry
else
raise(e)
end
end
end
alias_method_chain :load, :rails_classloader
end
所有这一点归功于Matt Brown谁this code as a pastie并对上述现已发表的文章发表了评论: