sdsykes / slim_scrooge

SlimScrooge heavily optimises your database interactions
313 stars 25 forks source link

ArgumentError: undefined class/module SlimScrooge:: #11

Closed nesquena closed 13 years ago

nesquena commented 14 years ago

In our application, we are caching (using memcached) the results of a particular expensive query.

Rails.cache.write('some-expensive-query', @results)

When we do this, we get the following exception:

ArgumentError: undefined class/module SlimScrooge::
[GEM_ROOT]/gems/memcache-client-1.8.5/lib/memcache.rb:250:in `load'
[GEM_ROOT]/gems/memcache-client-1.8.5/lib/memcache.rb:250:in `get'
[GEM_ROOT]/gems/memcache-client-1.8.5/lib/memcache.rb:886:in `with_server'
[GEM_ROOT]/gems/memcache-client-1.8.5/lib/memcache.rb:246:in `get'
[GEM_ROOT]/gems/activesupport-2.3.9/lib/active_support/cache/mem_cache_store.rb:63:in `read'
[GEM_ROOT]/gems/activesupport-2.3.9/lib/active_support/cache/strategy/local_cache.rb:39:in `read'

Any ideas on why retrieving the records from memcached would cause this exception to popup? Anyway to work around this issue? (Disable slim_scrooge for this query, if needed)?

sdsykes commented 14 years ago

I don't know why that would happen. Here is me trying to reproduce it with memcached:

  ruby-1.8.7-p248 > 2.times{Rails.cache.write("cc",Country.find(:last))}
  => 2  # don't have to do it twice, just to demo slim scrooge optimisation
  ruby-1.8.7-p248 > Rails.cache.read("cc")
  => #<Country id: 380, date: nil, country: "England", continent: "Europe", parent_country: "United
  Kingdom", official_name: "", status: "", highest_point: "Scafell Pike", height: 978> 

So that works ok.

The error suggests that memcached is trying to unmarshal a class that it doesn't have access to. Are you doing this in a background process or similar?

nesquena commented 14 years ago

I wish I could give you more valuable information to help you debug. After I disabled slim_scrooge I started seeing:

ArgumentError: undefined class/module Mysql::Result::RowHash
[GEM_ROOT]/gems/memcache-client-1.8.5/lib/memcache.rb:250:in `load'
[GEM_ROOT]/gems/memcache-client-1.8.5/lib/memcache.rb:250:in `get'
[GEM_ROOT]/gems/memcache-client-1.8.5/lib/memcache.rb:886:in `with_server'
[GEM_ROOT]/gems/memcache-client-1.8.5/lib/memcache.rb:246:in `get'
[GEM_ROOT]/gems/activesupport-2.3.9/lib/active_support/cache/mem_cache_store.rb:63:in `read'
[GEM_ROOT]/gems/activesupport-2.3.9/lib/active_support/cache/strategy/local_cache.rb:39:in `read'

Then I disabled slim_attributes and then this error went away altogether. Back with slim_scrooge enabled, I kept getting:

ArgumentError: undefined class/module SlimScrooge::
[GEM_ROOT]/gems/memcache-client-1.8.5/lib/memcache.rb:250:in `load'
[GEM_ROOT]/gems/memcache-client-1.8.5/lib/memcache.rb:250:in `get'
[GEM_ROOT]/gems/memcache-client-1.8.5/lib/memcache.rb:886:in `with_server'
[GEM_ROOT]/gems/memcache-client-1.8.5/lib/memcache.rb:246:in `get'
[GEM_ROOT]/gems/activesupport-2.3.9/lib/active_support/cache/mem_cache_store.rb:63:in `read'
[GEM_ROOT]/gems/activesupport-2.3.9/lib/active_support/cache/strategy/local_cache.rb:39:in `read'

We are on REE 1.8.7 with Passenger (2) + Nginx and Memcache-Client 1.8.5. On Rails 2.3.9. I am not doing this in a background process, it is simply part of a method in the model (invoked in the controller):

results = Rails.cache.fetch("some-key-here") {
    self.named_scopes_here(true).and_other_scopes(false).
    paginate(:page => options[:page], :per_page => 30)
}

Can you think of anything I might be doing wrong here?

sdsykes commented 14 years ago

Firstly, as you are using mysql then almost certainly you will do better just using slim_attributes rather than both (I did some benchmarks for that). But anyway, they do work together if needed.

The problem here is definitely that Slim_whichever is not loaded when the unmarshal due to reading the cache is happening.

Where exactly are you loading Slim? And when do you get this message - on a request?

nesquena commented 14 years ago

You recommend I just use slim_attributes then and eschew the use of slim_scrooge, at least according to your benchmarks?

I agree the issue here is that they are not loaded when the unmarshal occurs. I just don't understand why they are not loaded.

I am loading slim attributes in my Rails 2.3.9 app using bundler (for 2.3.9):

# Gemfile
gem 'slim_scrooge',    :group => [:development, :staging, :production]
gem 'slim-attributes', :group => [:development, :staging, :production]

I get this message on a rails request when the items are fetched from the cache. (hoptoad exception about a rails controller action). I am just stumped as to why this happens. We are using passenger, so perhaps it is related to smart spawning? I don't know I was just stumped so hoping posting here could help solidify the issue. I hate to have to stop using slim_attributes because of this one caching problem.

sdsykes commented 14 years ago

Regarding which to use, if your database is local I recommend just slim attributes. For slim_scrooge, the expense of tracking and reducing the queries will not be paid back as you are using slim attributes to avoid the creation of unnecessary ruby objects anyway.

Somehow I feel certain this is a bundler autoload issue. For SlimScrooge, as an experiment, try placing the costant SlimScrooge somewhere (perhaps in your environment.rb file) For slim attributes, as I don't define a SlimAttributes constant (and I probably should), try

# Gemfile
gem 'slim-attributes', :require_as => []

# environment.rb
Rails::Initializer.run do |config|
  # ...
  config.gem 'slim-attributes'
  # ...
end

Let me know what happens. I will try to reproduce in the mean time.

sdsykes commented 14 years ago

More, I have tried to reproduce with bundler. If you have

        @bundler_loaded ||= Bundler.require :default, Rails.env

in your load_gems method (added in boot.rb), then your bundled gems should all be loaded correctly.

This seems to work ok for me - are you using this same code?

nesquena commented 14 years ago

To be clear, everything is loaded alright in the application overall. I had been using these gems in production with the site for a while. We recently introduced caching for these records and only here after the records are retrieved do we see an issue.

I do have that bundler integration line as described in the gembundler 2.3 guide here: http://gembundler.com/rails23.html

Thanks for trying to reproduce. I appreciate the quick responses and the willingness to help. I really don't know why this is happening, but I will try the config.gem explicit require you mentioned in your previous message. Perhaps that can help..

sdsykes commented 13 years ago

I'm going to close this issue - it's due to slim not being loaded when the content in unmarshalled, and I don't think there's anything I can do within this gem to fix that - it has to be external.

As a side note - I have earlier experienced issues with cached content and autoloading in rails, particularly with models which need to be referenced before instances are unmarshalled from the cache.