7

我有一个相当大的 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 客户端 gem,认为这可能是一个奇怪的错误,但这没有任何效果!谢谢。

4

5 回答 5

10

这是由乘客共享其与 Memcached 服务器的连接引起的。检查http://www.modrails.com/documentation/Users%20guide.html#_example_1_memcached_connection_sharing_harmful

解决方法是将Passenger's Rails spawn 更改为conservative.

于 2009-04-13T20:05:22.113 回答
1

我也遇到了这个问题,并且在缓存提供者的解组操作之前为每个类/模型添加了 require_dependency。也许在生产环境中这不是必需的,因为选项:config.cache_class 设置为 true,但在测试和开发中它是 false。

事实上,Memcache(是我正在使用的缓存提供程序)没有找到引用的类来执行解组然后引发此错误。

在这篇文章中对这个问题有一个更好的解决方案:http: //kballcodes.com/2009/09/05/rails-memcached-a-better-solution-to-the-undefined-classmodule-problem/

问候!

于 2010-11-17T22:57:46.480 回答
1

一些可能有帮助的事情:

  • 添加检测/日志记录以current_site准确查看返回的内容。
  • 您如何在 memcache 中指定键?您可能会不小心在两个不同的地方为两个不同的对象使用相同的键。
  • 用于memcached-tool host:port dump > /tmp/keys查看内存缓存中的实际内容。
  • 您的 memcached 位于防火墙后面,并且没有暴露在公共 IP 上,对吧?
于 2009-04-09T17:43:26.980 回答
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
于 2009-11-19T20:02:00.767 回答
0

添加评论以防其他人出现... kballcodes.com 网址不再有效(尽管您仍然可以通过archive.org访问它)。在该博客文章的评论中,有人描述了一种方法,如果 Marshal 首先抛出“未定义的类/模块”错误,则可以尝试加载有问题的对象。我在下面包含了该代码,并在代码示例下方引用了原作者。

将此添加到 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

这一切都归功于马特布朗,他把这段代码写成了一个馅饼,并评论了上面现在已经死掉的文章:

于 2012-02-14T02:47:48.217 回答