Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exception in View Freezes Rails #1525

Closed
ndemoreau opened this issue Jun 7, 2011 · 117 comments
Closed

Exception in View Freezes Rails #1525

ndemoreau opened this issue Jun 7, 2011 · 117 comments
Assignees
Milestone

Comments

@ndemoreau
Copy link

Hi,

since I installed rails 3.1.0, when some bugs occur, Webrick freezes for a couple of minutes when some bugs occur (not all bugs, apparently the 500 ones).

My gemfile looks like this:

source 'http://rubygems.org'

gem "rails", "3.1.0.rc1"

Asset template engines

gem 'sass'
gem 'coffee-script'
gem 'uglifier'
gem 'jquery-rails'

gem "simple-navigation"
gem 'ranked-model' #, :git => 'git@github.com:harvesthq/ranked-model.git'
gem 'formtastic'
gem 'validation_reflection'
gem "paperclip", "~> 2.3"
gem 'devise'
gem 'heroku'
gem "aws-s3"
gem "scoped_search"
gem "meta_search", :git => 'git://github.com/ernie/meta_search.git'
gem "kaminari"

group :production do
gem "pg", "~> 0.11.0"
gem 'therubyracer-heroku', '0.8.1.pre3'
gem 'exception_notification', :require => 'exception_notifier'
end

group :development, :test do
gem 'mysql2'
end

require 'csv'

Can anyone help me on this? Thanks,

Nicolas

@markhurlburt
Copy link

I've experienced this as well... It doesn't seem to happen consistently though.

My gems:

gem 'rails', '3.1.0.rc1'
gem 'sqlite3'
gem 'mysql2'
gem 'json'
gem 'sass'
gem 'coffee-script'
gem 'uglifier'
gem 'jquery-rails'
gem 'capistrano'
gem 'compass', :require=>false
gem 'hoptoad_notifier'
gem 'devise'
gem 'cancan'
gem 'simple_form', :git=>"git://github.com/plataformatec/simple_form.git", :branch=>"master"
gem 'nifty-generators'
gem "paperclip", "~> 2.3"
gem 'inherited_resources'
gem "nested_form", :git => "git://github.com/ak/nested_form.git"
gem "acts_as_list"
gem 'kaminari'
gem 'thinking-sphinx', :git => "git://github.com/freelancing-god/thinking-sphinx.git", :branch => 'rails3'
gem 'sprite-factory'
gem 'rmagick'

@ndemoreau
Copy link
Author

I agree. It's unconsistent. The problem is the same with Unicorn or Mongrel. When I look at the activity monitor, I can clearly see the "ruby" process using more and more ram memory, until total freeze when this happen. I still don't know the reason. What I'm sure is that the bug has nothing to do with an infinite loop or somtehing like that.

Strange behaviour as well is the fact that, when it doesn't freeze, instead of being redirected to a page with details about the error, I'm redirected to the 500.html page, like in production.

@utkarshkukreti
Copy link
Contributor

@ndemoreau, are you using the Rails HTTP streaming by any chance?

@ndemoreau
Copy link
Author

Correct. I disabled it and now, i'm not redirected to the 500.html page anymore and the freeze doesn't seem to happen anymore (I did very few tests).

Thanks! I keep you posted.

Nicolas.

On 8 juin 2011, at 10:57, utkarshkukreti wrote:

@ndemoreau, are you using the Rails HTTP streaming by any chance?

Reply to this email directly or view it on GitHub:
#1525 (comment)

@ndemoreau
Copy link
Author

Just to let you know that it seems to be more stable but it is still not totally fixed yet. It just freezed when I mistyped an input on a simple_form form: <%= input.tel ... %>

@a-chernykh
Copy link
Contributor

+1 on this.

I am using the edge Rails and when the error is raised in the view then Rails freezes (eats more and more CPU and memory). When I hit Ctrl-C in console then the error is outputted to the console. I am on Mac OS X Snow Leo and using the latest Ruby 1.9.2. My server is Mongrel. I've also attached some 'dtruss' output here: https://gist.github.com/1016728

@tarmolehtpuu
Copy link

This issue is really annoying, the memory usage grows so fast it becomes quite difficult to even switch to a terminal window to kill the process. I tried to find the source of the problem, but I'm not that familiar with Rails codebase and ruby-prof isn't able to complete the dump file once things blow up (waited a good 15 minutes with my rsize growing to ~4GB).

Hoping that this will help a little bit in solving the problem then here's what I tried and figured out.

First create a view that uses assets and renders OK (without errors):

= stylesheet_link_tag :admin
= javascript_include_tag :admin

This should be OK

Then create a view that has an error like the one below:

= this_should_blow_up

Environment: OS X Snow Leopard, 1.9.2, Thin, Rails 3.1.0 RC4.

@adamjack
Copy link

adamjack commented Jul 7, 2011

Yeah, this does make development (porting to 3.1) tricky. I've found that if I CTRL-C the server sometimes I do get an error message output, which helps me track down that one problem to inch forward. Not fun.

I am also seeing this with Passenger.

I am using RoR 3.1 RC 4

@spastorino
Copy link
Contributor

Is this still an issue using rails from git 3-1-stable branch?

@a-chernykh
Copy link
Contributor

Yeah, still reproducible, but now better (6-7 secs until I see the error in browser). Workaround is to put this code in development.rb:

  config.after_initialize do
    module SmallInspect
      def inspect
        "<#{self.class.name} - tooooo long>"
      end
    end
    [ActionDispatch::RemoteIp::RemoteIpGetter, OmniAuth::Strategies::Facebook, ActionController::Base, Warden::Proxy].each do |klazz|
      klazz.send(:include, SmallInspect)
    end
  end

@spastorino
Copy link
Contributor

Can you share with us an application where we can try to reproduce the error?

@a-chernykh
Copy link
Contributor

Unfortunately, I can not share it with you because it's proprietary. I simply have HomeController#index action. In index.html.erb I place a call:

<% non_existing_method %>

It takes 7 secs to render the error in browser and console without the workaround code. And it takes 2 secs to render the error with workaround code. My Gemfile:

source 'http://rubygems.org'

gem 'rake', '0.8.7'
gem 'rails', :git => 'https://github.com/rails/rails.git', :branch => '3-1-stable'
gem 'mysql', '2.8.1'
gem 'jquery-rails', '1.0.7'
gem 'devise', :git => 'https://github.com/plataformatec/devise.git'
gem 'mini_magick', :git => 'https://github.com/AndreyChernyh/mini_magick.git' # , :path => '~/projects/gems/mini_magick'
gem 'fog', :git => 'https://github.com/AndreyChernyh/fog.git'
gem 'carrierwave', :git => 'https://github.com/AndreyChernyh/carrierwave.git'
gem 'faraday', '0.6.1'
gem 'oa-oauth', '0.2.6', :require => 'omniauth/oauth'
gem 'oa-openid', '0.2.6', :require => 'omniauth/openid'
gem 'oauth', '~> 0.4.0'
gem 'kaminari', '0.12.4'
gem 'exception_notification_rails3', :require => 'exception_notifier'
# TODO check if the official gem updated
gem 'grouped_validations', :git => 'https://github.com/adzap/grouped_validations.git'
gem 'memcache-client', '1.8.5'
gem 'acts-as-taggable-on', :git => 'https://github.com/denisj/acts-as-taggable-on.git'
gem 'gravtastic', '3.1.0'
gem 'twitter', '1.4.1'
gem 'fbgraph', '1.8.0'
gem 'thinking-sphinx', '2.0.5'
gem 'ts-datetime-delta', '1.0.2', :require => 'thinking_sphinx/deltas/datetime_delta'
gem 'sass-rails'
gem 'whenever', '0.6.7', :require => false
gem 'newrelic_rpm', '3.1.1.beta1'
gem 'configatron', '2.8.0'
gem 'delayed_job', '2.1.4'
gem 'yui-compressor', '0.9.6'
#gem 'mailman', '0.4.0'

# admin
gem 'meta_search', '>= 1.1.0.pre'
gem 'activeadmin', :git => 'https://github.com/gregbell/active_admin.git'

# caching
gem 'hiredis', '~> 0.3.1'
gem 'redis', '~> 2.2.0', :require => ["redis/connection/hiredis", "redis"]
gem 'redis-store', '1.0.0.rc1'

group :development, :test do
  gem 'mongrel'
  gem 'rspec-rails', '2.6.1.beta1'
  gem 'ruby-prof'
end

group :test do
  gem 'factory_girl_rails', '1.0.1'
  gem 'shoulda-matchers', :git => 'https://github.com/thoughtbot/shoulda-matchers.git'
  gem 'autotest-rails', '4.1.0'
  gem 'capybara', :git => 'git://github.com/jnicklas/capybara.git'
  gem 'timecop', '0.3.5'
  gem 'launchy'
end

group :production, :staging do
  gem 'unicorn'
end

@iHiD
Copy link
Contributor

iHiD commented Jul 21, 2011

I'm on master and I've still got this. It happens every time you call a non-existent method as @AndreyChernyh said.

Want me to try on the stable branch or should master have fixed it if stable has?

This app is also proprietary and it's massive, but I'm happy to provide any traces or info that might be useful.

My Gemfile looks like this:

source 'http://rubygems.org'

gem 'rails', :git => "git://github.com/rails/rails.git"

gem 'mysql2'
gem 'rubyzip2'
gem 'libxml-ruby'
gem 'will_paginate', :git => "git://github.com/JackDanger/will_paginate.git" #"git://github.com/mislav/will_paginate.git"
gem 'cocaine'
gem 'paperclip', :git => "git://github.com/ihid/paperclip.git", :branch => "delayed_fog"
gem 'json'
#gem 'rmagick', "2.13.1"
gem 'hpricot'
gem 'ruby-openid'
gem 'exceptional'
gem 'memcache-client'
gem 'haml', :git => "git://github.com/ihid/haml.git"
gem 'sass-rails', :git => "git://github.com/rails/sass-rails.git"
#gem 'sass', :git => "git://github.com/nex3/sass.git"
gem 'bourbon', :git => "git://github.com/ihid/bourbon.git"
gem 'coffee-script'
gem 'uglifier'
gem 'jquery-rails'
gem 'pdfkit', "0.5.1"
gem 'aws-s3', :require => "aws/s3"
gem 'fog'
gem 'amazon-ec2'
gem 'oink'
gem 'foreigner', :git => 'git://github.com/matthuhiggins/foreigner.git'
gem 'bson_ext'
gem 'super_sti', :git => "git://github.com/ihid/super_sti.git"
gem 'belongs_to_enum', :git => "git://github.com/ihid/belongs_to_enum.git"
gem 'activemerchant', :git => "git://github.com/ihid/active_merchant.git"

group :test do
    gem 'ruby-debug19', :require => 'ruby-debug'
    gem 'rspec-rails'
    gem 'autotest'
    gem 'webrat'
end

group :development do
  #gem 'rails-dev-boost', :git => 'git://github.com/thedarkone/rails-dev-boost.git', :require => 'rails_development_boost'
end

group :production do 
  gem 'thinking-sphinx',
    :git     => 'git://github.com/freelancing-god/thinking-sphinx.git',
    :branch  => 'rails3',
    :require => 'thinking_sphinx'
end

@iHiD
Copy link
Contributor

iHiD commented Jul 21, 2011

This is the output I get if I kill the server with CTRL-C (the ^C are me holding down CTRL-C as my computer is totally unresponsive by this point).

^C^C^C^C^C^C^C^C[2011-07-21 16:29:00] ERROR NoMethodError: undefined method `shutdown' for nil:NilClass
    /Users/iHiD/.rvm/gems/ruby-1.9.2-p180/bundler/gems/rails-993d0f6477c6/activesupport/lib/active_support/whiny_nil.rb:48:in `method_missing'
^C^C^C^C^C^C/Users/iHiD/.rvm/gems/ruby-1.9.2-p180/bundler/gems/rails-993d0f6477c6/activesupport/lib/active_support/whiny_nil.rb:48:in `method_missing': undefined method `shutdown' for nil:NilClass (NoMethodError)
    from /Users/iHiD/.rvm/gems/ruby-1.9.2-p180/gems/rack-1.3.1/lib/rack/handler/webrick.rb:24:in `shutdown'
    from /Users/iHiD/.rvm/gems/ruby-1.9.2-p180/gems/rack-1.3.1/lib/rack/server.rb:259:in `block in start'
    from /Users/iHiD/.rvm/gems/ruby-1.9.2-p180/gems/rack-1.3.1/lib/rack/server.rb:320:in `call'
    from /Users/iHiD/.rvm/gems/ruby-1.9.2-p180/gems/rack-1.3.1/lib/rack/server.rb:320:in `block in write_pid'
    from script/rails:in `call'
^C^C^C^C^C^C^C^C^C^C^C

Started GET "/publications/1" for 127.0.0.1 at 2011-07-21 16:28:29 +0100
Processing by PublicationsController#show as HTML
  Parameters: {"id"=>"1"}
  User Load (0.5ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1
  Publication Load (0.2ms)  SELECT `publications`.* FROM `publications` WHERE `publications`.`id` = 1 LIMIT 1
Compiled ~/.rvm/gems/ruby-1.9.2-p180/gems/jquery-rails-1.0.12/vendor/assets/javascripts/jquery.js  (0ms)  (pid 6640)
Compiled ~/.rvm/gems/ruby-1.9.2-p180/gems/jquery-rails-1.0.12/vendor/assets/javascripts/jquery_ujs.js  (0ms)  (pid 6640)
Compiled ~/Projects/Work/meducation/app/assets/javascripts/jquery.ui.min.js  (0ms)  (pid 6640)
Compiled ~/Projects/Work/meducation/app/assets/javascripts/jquery.tools.min.js  (0ms)  (pid 6640)
Compiled ~/Projects/Work/meducation/app/assets/javascripts/jquery.tokeninput.js  (0ms)  (pid 6640)
Compiled ~/Projects/Work/meducation/app/assets/javascripts/jquery.jcrop.min.js  (0ms)  (pid 6640)
Compiled ~/Projects/Work/meducation/app/assets/javascripts/jquery.iframe-transport.js  (0ms)  (pid 6640)
Compiled ~/Projects/Work/meducation/app/assets/javascripts/jquery.fileupload.js  (0ms)  (pid 6640)
Compiled ~/Projects/Work/meducation/app/assets/javascripts/general.js  (0ms)  (pid 6640)
Compiled ~/Projects/Work/meducation/app/assets/javascripts/meducation.js.coffee  (0ms)  (pid 6640)
Compiled ~/Projects/Work/meducation/app/assets/javascripts/ui.js.coffee  (0ms)  (pid 6640)
Compiled ~/Projects/Work/meducation/app/assets/javascripts/users.js.coffee  (0ms)  (pid 6640)
Compiled ~/Projects/Work/meducation/app/assets/javascripts/widgets.js.coffee  (0ms)  (pid 6640)
Compiled ~/Projects/Work/meducation/app/assets/javascripts/exam_room/practice/exams.js.coffee  (0ms)  (pid 6640)
Compiled ~/Projects/Work/meducation/app/assets/javascripts/exam_room/practice/questions.js.coffee  (0ms)  (pid 6640)
Compiled ~/Projects/Work/meducation/app/assets/javascripts/exam_room/practice/mcqs.js.coffee  (0ms)  (pid 6640)
Compiled ~/Projects/Work/meducation/app/assets/javascripts/exam_room/practice/sbas.js.coffee  (0ms)  (pid 6640)
Compiled ~/Projects/Work/meducation/app/assets/javascripts/publications.js.coffee  (0ms)  (pid 6640)
Compiled ~/Projects/Work/meducation/app/assets/javascripts/ecommerce.js.coffee  (0ms)  (pid 6640)
Compiled ~/Projects/Work/meducation/app/assets/javascripts/application.js  (0ms)  (pid 6640)
Compiled ~/Projects/Work/meducation/app/assets/stylesheets/application.css.scss  (0ms)  (pid 6640)
  Rendered publications/show.html.haml within layouts/application (30347.5ms)
Completed 500 Internal Server Error in 30794ms

ActionView::Template::Error (undefined local variable or method `asdwqe' for #<#<Class:0x0000010c28b330>:0x0000010c2872f8>):
    69:         
    70:         #publication_container    
    71:             
    72:             -non_existant.each do |i|
    73:                 -x
    74: 
    75: 
  app/views/publications/show.html.haml:72:in `_app_views_publications_show_html_haml___2654011636592586608_2249469060'

  Rendered /Users/iHiD/.rvm/gems/ruby-1.9.2-p180/bundler/gems/rails-993d0f6477c6/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.erb (120.3ms)
  Rendered /Users/iHiD/.rvm/gems/ruby-1.9.2-p180/bundler/gems/rails-993d0f6477c6/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (3.9ms)
  Rendered /Users/iHiD/.rvm/gems/ruby-1.9.2-p180/bundler/gems/rails-993d0f6477c6/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.erb within rescues/layout (210.9ms)
^C^C^C^C^C^C/Users/iHiD/.rvm/gems/ruby-1.9.2-p180/bundler/gems/rails-993d0f6477c6/activesupport/lib/active_support/whiny_nil.rb:48:in `method_missing': undefined method `shutdown' for nil:NilClass (NoMethodError)
    from /Users/iHiD/.rvm/gems/ruby-1.9.2-p180/gems/rack-1.3.1/lib/rack/handler/webrick.rb:24:in `shutdown'
    from /Users/iHiD/.rvm/gems/ruby-1.9.2-p180/gems/rack-1.3.1/lib/rack/server.rb:259:in `block in start'
    from script/rails:in `call'
^C^C

@iHiD
Copy link
Contributor

iHiD commented Jul 21, 2011

Digging into this deeper, I'm also sporadically getting the following. It may or may not be related.

(Update: now I've applied @AndreyChernyh's hack, I get this ever time a page fails.)

Error during failsafe response: incompatible character encodings: UTF-8 and ASCII-8BIT
  /Users/iHiD/.rvm/gems/ruby-1.9.2-p180/bundler/gems/rails-993d0f6477c6/actionpack/lib/action_dispatch/middleware/show_exceptions.rb:132:in `block in log_error'
  /Users/iHiD/.rvm/gems/ruby-1.9.2-p180/bundler/gems/rails-993d0f6477c6/activesupport/lib/active_support/deprecation/reporting.rb:20:in `silence'
  /Users/iHiD/.rvm/gems/ruby-1.9.2-p180/bundler/gems/rails-993d0f6477c6/actionpack/lib/action_dispatch/middleware/show_exceptions.rb:130:in `log_error'
  /Users/iHiD/.rvm/gems/ruby-1.9.2-p180/bundler/gems/rails-993d0f6477c6/actionpack/lib/action_dispatch/middleware/show_exceptions.rb:65:in `render_exception'
  /Users/iHiD/.rvm/gems/ruby-1.9.2-p180/bundler/gems/rails-993d0f6477c6/actionpack/lib/action_dispatch/middleware/show_exceptions.rb:60:in `call'
  /Users/iHiD/.rvm/gems/ruby-1.9.2-p180/bundler/gems/rails-993d0f6477c6/railties/lib/rails/rack/logger.rb:13:in `call'
  /Users/iHiD/.rvm/gems/ruby-1.9.2-p180/gems/rack-1.3.1/lib/rack/methodoverride.rb:24:in `call'
  /Users/iHiD/.rvm/gems/ruby-1.9.2-p180/gems/rack-1.3.1/lib/rack/runtime.rb:17:in `call'
  /Users/iHiD/.rvm/gems/ruby-1.9.2-p180/bundler/gems/rails-993d0f6477c6/activesupport/lib/active_support/cache/strategy/local_cache.rb:72:in `call'
  /Users/iHiD/.rvm/gems/ruby-1.9.2-p180/gems/rack-1.3.1/lib/rack/lock.rb:15:in `call'
  /Users/iHiD/.rvm/gems/ruby-1.9.2-p180/bundler/gems/rails-993d0f6477c6/actionpack/lib/action_dispatch/middleware/static.rb:53:in `call'
  /Users/iHiD/.rvm/gems/ruby-1.9.2-p180/bundler/gems/rails-993d0f6477c6/railties/lib/rails/engine.rb:454:in `call'
  /Users/iHiD/.rvm/gems/ruby-1.9.2-p180/bundler/gems/rails-993d0f6477c6/railties/lib/rails/rack/content_length.rb:16:in `call'
  /Users/iHiD/.rvm/gems/ruby-1.9.2-p180/bundler/gems/rails-993d0f6477c6/railties/lib/rails/rack/log_tailer.rb:14:in `call'
  /Users/iHiD/.rvm/gems/ruby-1.9.2-p180/gems/rack-1.3.1/lib/rack/handler/webrick.rb:59:in `service'
  /Users/iHiD/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/webrick/httpserver.rb:111:in `service'
  /Users/iHiD/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/webrick/httpserver.rb:70:in `run'
  /Users/iHiD/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/webrick/server.rb:183:in `block in start_thread'

@ghost ghost assigned tenderlove Jul 21, 2011
@xaviershay
Copy link
Contributor

I had this problem on an app I no longer work on, but we worked around with the #inspect monkey patch provided above.

This issue was potentially made harder to reproduce by 5b88014 that filters out most of the rack stuff from the env dump.

It doesn't fix the root problems though, of which there are two:

  1. #inspect on an ActionController::Base instance is 33K (!!) on a blank rails app. This is totally unhelpful. The opposite extreme (only show the class name) would be more useful and not misleading.
  2. The error page blindly renders the inspect of everything in the session and a lot of stuff in the environment. This is potentially megabytes of data, most of which is hidden by default, and given it's volume likely not interesting in the majority of cases. While generating the inspect output can potentially take a long time (see point 1), changing debug_hash in actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb to truncate the output to an arbitrary length (100 chars?) seems reasonable to me.

Happy to provide a patch for either or both of these suggestions @spastorino if you agree.

@iHiD
Copy link
Contributor

iHiD commented Jul 23, 2011

Are you guys aware of why this is only happening when the error is a missing method? Parse errors and general exceptions are being handled fine. Is a different template rendered for this etc?

Could we maybe mimic the other exception behaviours here?

Excuse my questions rather than solutions - I don't know this bit of the codebase at all and am too bogged down with deadlines to explore it right now. Sorry.

@Stefano1990
Copy link

I experience the issue with unicorn as well as webrick. My trick is to spot it before the memory monster goes past the 1GB.. from years of CounterStrike I tend to have a good reaction time.. ha ha..

Anyway it only happens on method_missing errors for me, typical typo errors. When making a new app it doesnt seem to happen in webrick or unicorn. I only tested this for a few minutes.

Maybe important is also the information that it doesnt only happen on the view layer. I also had this happen in a model, 100% reproducible. Unfortunately I deleted that bit of code :/ (I know Im a dummy...) I will post some code if i can reproduce it again.

@tarmolehtpuu
Copy link

I've managed to capture a couple stack traces - http://pastie.org/2268985

@tarmolehtpuu
Copy link

When monkey patching rack-mount/lib/rack/mount/route.rb inspect to not call @app.inspect at least the problem goes away, along with some debug info :(

@tenderlove
Copy link
Member

@xaviershay I'm happy with that. Can you put together a patch?

@tanelsuurhans
Copy link

Seems that I managed to fix this (at least I am not able to reproduce this issue anymore).
I created a pull request with the change: #2264

It seems that when a Template:Error is raised from rendering the actual view, the layout rendering fails with calling .html_safe on nil content. This in turn raises another error, which then causes the whole loop to repeat until the host machine runs out of RAM.

@xaviershay
Copy link
Contributor

Great find @tanelsuurhans. I'm still going to put together a patch for my suggestions as I still think they're worthwhile additions.

xaviershay added a commit to xaviershay/rails that referenced this issue Jul 26, 2011
The default includes all instance variables which is many kilobytes long
and takes too long to generate, as well as being just plain not useful.

The original impetus for this change was the development 500 page taking
ages to render, in part because of the potentially massive amount of
data that inspect would be generating and displaying. This was mitigated
somewhat by 5b88014, though this commit
fixes one of the root problems and has the added benefit of being more
useful when debugging in console.

References rails#1525.
@xaviershay
Copy link
Contributor

Pull request for shorter inspect output for Rails::Engine (the @app.inspect culprit from above), and AbstractController. Adds ActiveSupport::ShortInspect so others can use it also: #2269

Probably not going to get around to the #debug_hash changes I suggested just at the moment. /cc @tenderlove

@tarmolehtpuu
Copy link

I debugged this problem some more, it seems to happen in C code - action_view/template/error.rb#initialize never returns, more accurately the call to NameError.message never returns: super(original_exception.message).

I've tried this also with JRuby (1.6.3) and everything works, the following is the result from original_exception.message:

undefined local variable or method `foo' for #<#Class:0x174cff77f:0x2e20a282>

For some reason 1.9.2-p0 and 1.9.2-p290 are unable to call name_err_mesg_to_str without going into an endless loop and concating to a huge string buffer. I've captured a couple of C level stack traces with GDB also and I think it looks like the string is already over 8 MB.

What I suspect is that while name error is looping instance variables there's some sort of circular reference or edge case that causes it to keep looping endlessly (no recursion since stack overflow doesn't happen).

I also pastied the C stack traces: http://pastie.org/2274529 and http://pastie.org/2274530

I'll try to go through the C code a bit more when I get the chance, meanwhile hope that this helps a bit in finding the cause of the problem.

@tenderlove
Copy link
Member

@tarmolehtpuu can you consistently reproduce the error? If so, can you push an app to github that I can use to repro?

@daliborfilus
Copy link

I got into this loop too since 3.1.0.rc1.
Now with rc5 using passenger 3.0.3 on ruby 1.8.7 it's not really the same case, the waiting is long, but not endless like in rc1-4 for me.

On rc4, I had to kill the process and relaunch passenger.

Mainly caused by "undefined method" errors, I think when the app crashes for something else, like syntax err, it is OK. (sorry if this is already known.)

3.1.0.rc1+
ruby 1.8.7 (2010-01-10 patchlevel 249) [universal-darwin11.0] && ruby 1.8.7 EE 2011.3
passenger 3.0.3

@tarmolehtpuu
Copy link

@tenderlove, I'm able to reproduce it, but as usual the app is proprietary and I can't share it I think (I'll have to check). I've been trying to reproduce this with a fresh application, no luck so far. I'll try some more over the weekend.

@tanelsuurhans
Copy link

@DriesS: I really have to ask - why on earth are you still using 1.8.7 with Rails 3.2.1? Afaik Rails dropped official support for 1.8.7 from 3.x onwards. I really suggest you upgrade your ruby version, you will get insane performance boots from using 1.9.3

@betelgeuse
Copy link

@tanelsuurhans rails supports 1.8.7 until 4.0

@tanelsuurhans
Copy link

Okay, I was on that one then. Doesn't really change the fact that 1.8.7 is dog slow compared to 1.9.3, not to mention the memory usage :)

As a side note - I've encountered this bug a couple of times on a 3.2.1 project too, although its not as bad as it was with 3.0.x, just eats a up a bit of memory and spits out the TemplateError.

@tarmolehtpuu
Copy link

never ending issue :)

Would it make sense to write custom inspect methods for rails core classes (at least the huge ones) to make this go away?

@kranzky
Copy link

kranzky commented Feb 15, 2012

@tarmolehtpuu I think that an idiom of "implement inspect for complex classes" is good practice in general; after all, who is inspect for (developers, right)? So the default implementation, which, in our case, returns a 20MB string for the view, is pretty useless! I mean, 20MB is the complete works of shakespeare, the bible, all the sherlock holmes stories, and a bunch of other stuff. Hence my comment about separating symptom from cause above: #1525 (comment)

@tanelsuurhans all evidence we have to have to hand is that 1.9.x performance is worse than ree 1.8.7 for our app; it's quite likely GC related; we've not had enough time to investigate

@joshgoebel
Copy link
Contributor

Ping. Seriously. Still no fix for this in Rails 3.2.1? I'm find the RouteSet hack (added via initializer) works for me.

module ActionDispatch
  module Routing
    class RouteSet
      alias inspect to_s
    end
  end
end

@joevandyk
Copy link
Contributor

I created a sample app that shows how rails hangs when getting a view error. https://github.com/joevandyk/rails-view-errors-hanging Essentially I created an empty Rails 3.1.3 app with a couple thousand routes and put an undefined method call in the view. I also made a 3.2 branch -- that one seems to hang for much longer.

For me, it only hangs for 5-6 seconds, but I'm sure the root cause of the slowness is the same as mentioned above where Rails can hang for minutes for larger apps.

As mentioned in the README, I'm positive this problem can show itself without having a thousand+ routes, but the slowness is fixed by the above Routeset fix.

@akashkamboj
Copy link

I am using Rails 3.2.1 and the same is happening with me. whenever a method isn't find it takes forever to not throw the error. And memory usage going up and up and it almost use all of my system memory if i dont kill the server manually and sometimes killing the server doesnt work easily. Please we need a fix.

@barttenbrinke
Copy link
Contributor

Encountered this problem yesterday in production :( RouteSet hack works for me now.

@kranzky
Copy link

kranzky commented Feb 21, 2012

Out of curiosity, I've had a bit more of a look into this issue. The problem is internal to the Ruby interpreter; Rails isn't scrubbing this exception message as suspected by @tanelsuurhans seven months ago.

The root cause is name_err_mesg_to_str, which always calls the inspect method of the object throwing the exception when constructing the message for a NameError or a NoMethodError. Which is pretty much what @tarmolehtpuu found in his first debugging session. This is the (1.9.2) code:

d = rb_protect(rb_inspect, obj, 0);
if (NIL_P(d) || RSTRING_LEN(d) > 65) {
  d = rb_any_to_s(obj);
}
desc = RSTRING_PTR(d);

...

if (desc && desc[0] != '#') {
  d = d ? rb_str_dup(d) : rb_str_new2(desc);
  rb_str_cat2(d, ":");
  rb_str_cat2(d, rb_obj_classname(obj));
}

args[0] = mesg;
args[1] = ptr[2];
args[2] = d;
mesg = rb_f_sprintf(NAME_ERR_MESG_COUNT, args);

That is:

  • Call inspect on the object that raised the exception
  • If the string returned is nil, or is more than 65 characters long, then call rb_any_to_s, which returns a string of the form #<CLASSNAME:ADDRESS>
  • If the string doesn't start with a #, then add the class name to the end of the string
  • Build the exception message via rb_f_sprintf

Now, when a NameError or NoMethodError is thrown from a view, any access of the message of the resulting exception object will cause name_err_mesg_to_str to be invoked, which in turn will call inspect on the object which raised the exception, very probably discarding the results.

The default implementation of inspect, as we now all know, can be resource hungry for large, complex objects. One perfectly reasonable fix, I think, would therefore be for name_err_mesg_to_str to call rb_inspect only if it had been overridden (that is, to never call the default implementation for an object). But that's as maybe. The fix for us is to ensure that we don't allow the default implementation of inspect to be called. Which is as simple as overriding it. Which is what the "RouteSet Hack" does.

Here's a simple test that replicates the issue in plain Ruby:

def test_slow_inspect
  require 'benchmark'
  SlowInspect.new.raise_name_error
rescue NameError => e
  time = Benchmark.realtime { puts e.message }
  puts "(done in #{(time*1000).to_i} ms)"
end

class SlowInspect
  def initialize(l=0)
    @foo = []
    10.times { @foo << ( l > 4 ? self : SlowInspect.new(l+1) ) }
  end
  def raise_name_error
    shazbut
  end
end

test_slow_inspect

class SlowInspect
  alias inspect to_s
end

test_slow_inspect

which prints the following on my machine:

undefined local variable or method `shazbut' for #<SlowInspect:0x105213990>
(done in 4593 ms)
undefined local variable or method `shazbut' for #<SlowInspect:0x10499fae8>
(done in 0 ms)

Note that the result of calling e.message here is identical (well, apart from the address of the object); the only difference is that we're reducing the overhead of the call to inspect by overriding its default implementation.

In pure Ruby terms, "implement inspect for complex classes" is a good idiom. And, if you're bothering to do that, then "keep the length of the string returned by inspect no more than 65 characters" is a useful corollary, as it will yield more informative error messages for NameError and NoMethodError exceptions.

carlosantoniodasilva pushed a commit to carlosantoniodasilva/rails that referenced this issue Feb 23, 2012
@joevandyk
Copy link
Contributor

The fix for this bug has arrived on the 3.2 and 3.1 stable branches.

arturopie pushed a commit to arturopie/rails that referenced this issue Mar 28, 2012
yahonda pushed a commit to yahonda/rails that referenced this issue Mar 29, 2012
@tgautier-silicon
Copy link

For those who might stumble upon dirty fixes for this issues in "old" projects, I can confirm that this issue has been fixed in 3.2.3.

The changelog doesn't cleary stipulates it (you can't look up #1525).

@barttenbrinke
Copy link
Contributor

I always create the changelog on the fly using github : v3.2.2...v3.2.3
There it says it got included :)

@joevandyk
Copy link
Contributor

The changelog does say the cause for the bug (routeset inspection) was
fixed. But unfortunately it doesn't mention the actual bug (freezing,
memory growth on view errors).

On Apr 18, 2012, at 3:40 AM, Thomas Gautier
reply@reply.github.com
wrote:

For those like me who're used to check changelogs, I confirm that this issue has been fixed in 3.2.3 even if the changelog http://weblog.rubyonrails.org/2012/3/30/ann-rails-3-2-3-has-been-released/ doesn't say so.


Reply to this email directly or view it on GitHub:
#1525 (comment)

QuantumCatgirl pushed a commit to alphagov/whitehall that referenced this issue Apr 8, 2014
The view context is so large that in some cases (eg. when an exception is raised
in a template where multiple presenters are referencing the view_context), the
ruby process spins out eating more and more memory before either generating an
enormous half-gig log or falling over altogether. This suppresses inspect messages
on ActionView::Base allowing exceptions to raise without issue.

More info on the issue here: rails/rails#1525 (comment)
hashrocketeer pushed a commit to hashrocket/decent_exposure that referenced this issue Feb 8, 2016
Calling `inspect` on Active Record collections fires up a sql query that
reads the entire table. `NameError` exceptions call inspect on all local
controller instance variables, which in turn can cause application to
hang.

This has been reported in Rails:
rails/rails#1525

Closes #127
hashrocketeer pushed a commit to hashrocket/decent_exposure that referenced this issue Feb 8, 2016
Calling `inspect` on Active Record collections fires up a sql query that
reads the entire table. `NameError` exceptions call inspect on all local
controller instance variables, which in turn can cause application to
hang.

This has been reported in Rails:
rails/rails#1525

Closes #127
hashrocketeer pushed a commit to hashrocket/decent_exposure that referenced this issue Feb 8, 2016
Calling `inspect` on Active Record collections fires up a sql query that
reads the entire table. `NameError` exceptions call inspect on all local
controller instance variables, which in turn can cause application to
hang.

This has been reported in Rails:
rails/rails#1525

Closes #127
@ivoanjo
Copy link

ivoanjo commented Feb 22, 2023

Out of curiosity (since so many others reference this PR when discussing inspect + exception), Ruby 3.3 will fix this issue: https://bugs.ruby-lang.org/issues/18285

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests