Rails view ivars spontaneously combusting in ruby 1.9

395 Views Asked by At

I have a Rails 3 / ruby 1.9.2 webapp. Every so often - and it might only be 1 request in 100000 - I get an error report that I can't explain.

The exact error varies, but they seem to be along the lines of having an instance variable in my view suddenly become nil. The clearest instance of this occurred recently, where this code in a helper -

 @swf_object_count||=0
 @swf_object_count+=1

- raised "NoMethodError: undefined method `+' for nil:NilClass". However, note that the errors are not limited to this case, and these two lines of code are meant only for illustration, not as something that can be worked around to 'solve' the problem.

The error is basically impossible to reproduce : I have never seen it myself, only seen the error reports resulting from it. I believe the error first appeared when we switched from REE to ruby 1.9.2.

Miscellaneous details that may or may not be relevant:

  • We're running ruby1.9.2p290 on Solaris 10, using unicorn forked instances
  • We're not using threads or fibers (correction: our app itself doesn't, but we do use NewRelic, which has a background thread for collecting/posting stats.)
  • We have a mix of .haml & .erb views, but I've only ever seen this occur from .haml. (We don't have many .erbs, though)
  • I've never seen this occur in controller code
  • I've occasionally seen errors regarding "undefined method 'foomethod' for Bar", when I know for a fact that we never call Bar.foomethod. It might be possible that this is related to the bug described above, where a Bar object spontaneously replaced a Foo ivar.

I'm pretty stumped on tracking this down. Any suggestions, or has anyone seen anything that sounds similar?

2

There are 2 best solutions below

7
On

my first thought was threads or fibers -- but you said you don't use them. hmm... could this be triggered from a stale session?

this is really a very broad and loosely defined question..

Perhaps you could write a script to analyze your log files, and try to narrow down when / in which routes this happens. But that's pretty hard to debug also, because you probably made a couple of code changes along the way, some of which have produced valid errors which may look similar.

It can happen that Unicorn instances die and then they get restarted.. this could upset the current session. This might be something you may want to experiment with -- e.g. use a test-environment with two unicorns, kill one mid-session and see how that affects your logs.

You should probably install a facility where your Rails server emails you a detailed log record whenever an exception is triggered.. that's probably the best way to get more visibility into what's happening there..

e.g.: this Gem in your Gemfile:

# Receive exception notifications from production
gem 'exception_notification_rails3', :require => 'exception_notifier'

and in your config/environments/production.rb file:

  config.middleware.use ExceptionNotifier,
    :email_prefix => "[Exception] ",
    :sender_address => %{"Exception Notifier" <[email protected]>},
    :exception_recipients => %w{[email protected] [email protected]}

See also: https://github.com/railsware/exception_notification

8
On

Manipulating view ivars in your helpers is a terrible idea. I'm not sure why you're getting the concurrency issues you're getting, but I suspect they will go away if you structure your code differently.

Perhaps you can just have the helper calculate the increment values, and in your view do something like

@swf_object_count + swf_increment_helper_value