No commit activity in last 3 years
No release in over 3 years
An easy way to handle stale object errors in Rails by retrying the entire request.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Runtime

>= 0
 Project Readme

Stale Object Destroyer¶ ↑

An easy way to handle stale object errors in Rails by retrying the entire request.

If you’re using optimistic locking your ActiveRecord models you’ve probably run across the ActiveRecord::StaleObjectError. It is raised when a race condition is detected.

So how do you handle ActiveRecord::StaleObjectError? Rails documentation has this to say.

You're then responsible for dealing with the conflict by rescuing the 
exception and either rolling back, merging, or otherwise apply the business 
logic needed to resolve the conflict.

In most applications, you simply need to retry the thing that failed and make sure you don’t use any stale values when trying again. That last bit can prove rather tricky with the numerous caching techniques employed in high performance Rails applications.

Stale Object Destroyer provides an easy way for you to start the entire request over to ensure no stale objects will be operated on. It handles this entirely inside of Rails though, so no additional client requests will be made.

As far as your code knows, the user just retried the request a few times in hopes of success.

As far as your user knows, your site did nothing out of the ordinary.

By default the request will be attempted 3 times. You can override this on a controller basis by defining a class method on the controller that returns an integer for retry_attempts.

class ApplicationController < ActionController::Base

def self.retry_attempts
  5
end

end

Examples¶ ↑

Stale Object Destroyer works by handling StaleObjectErrors at a much higher level in the request cycle so you will need to let them pass through your exception notification code.

def rescue_action_with_stale_object_reraise(exception)
  request.reraise_stale_object_errors(exception)
  rescue_action_without_stale_object_reraise(exception)
end
alias_method_chain :rescue_action, :stale_object_reraise

If needed, you can inspect the request object to determine how many times the current action has been attempted or to find out if this is the last attempt.

request.attempt         # => 3
request.last_attempt?   # => false

A great use of request.attempt is to disable your caching library after a request has failed.

before_filter :cache_setup
def cache_setup
  SomeCacheLibrary.enable = request.attempt == 1
end

If you need to call something on the stale object when the error is encountered there is an after_stale_object_error callback you can use. Typically this is used to guarantee cache expiry in this event.

class User < ActiveRecord::Base
  after_stale_object_error :expire_cache
end

Install¶ ↑

As a Rails plugin.

./script/plugin install git://github.com/jqr/stale_object_destroyer.git

Prefer gems? Add this to your environment.rb and run the following command.

config.gem 'jqr-stale_object_destroyer', :lib => 'stale_object_destroyer', :source => 'http://gems.github.com'

$ rake gems:install
Homepage

github.com/jqr/versionable/tree/master

License

Copyright © 2008 Elijah Miller <elijah.miller@gmail.com> and Kristopher Chambers <kristopher.chambers@gmail.com, released under the MIT license.