jqr-stale_object_destroyer 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +1 -0
- data/Manifest +7 -0
- data/README.rdoc +58 -0
- data/Rakefile +21 -0
- data/init.rb +1 -0
- data/lib/stale_object_destroyer.rb +33 -0
- data/spec/spec_helper.rb +5 -0
- data/stale_object_destroyer.gemspec +34 -0
- metadata +75 -0
data/CHANGELOG
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
v0.0.1. Initial extraction.
|
data/Manifest
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
= Stale Object Destroyer
|
2
|
+
|
3
|
+
An easy way to handle stale object errors in Rails by retrying the entire request.
|
4
|
+
|
5
|
+
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.
|
6
|
+
|
7
|
+
So how do you handle ActiveRecord::StaleObjectError? Rails documentation has this to say.
|
8
|
+
|
9
|
+
You're then responsible for dealing with the conflict by rescuing the
|
10
|
+
exception and either rolling back, merging, or otherwise apply the business
|
11
|
+
logic needed to resolve the conflict.
|
12
|
+
|
13
|
+
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.
|
14
|
+
|
15
|
+
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.
|
16
|
+
|
17
|
+
As far as your code knows, the user just retried the request a few times in hopes of success.
|
18
|
+
|
19
|
+
As far as your user knows, your site did nothing out of the ordinary.
|
20
|
+
|
21
|
+
== Examples
|
22
|
+
|
23
|
+
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.
|
24
|
+
|
25
|
+
def rescue_action_in_public
|
26
|
+
request.reraise_stale_object_errors(exception)
|
27
|
+
|
28
|
+
# normal exception stuff, hoptoad etc.
|
29
|
+
end
|
30
|
+
|
31
|
+
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.
|
32
|
+
|
33
|
+
request.attempt # => 3
|
34
|
+
request.last_attempt? # => false
|
35
|
+
|
36
|
+
A great use of request.attempt is to disable your caching library after a request has failed.
|
37
|
+
|
38
|
+
before_filter :cache_setup
|
39
|
+
def cache_setup
|
40
|
+
SomeCacheLibrary.enable = request.attempt == 1
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
== Install
|
45
|
+
|
46
|
+
As a Rails plugin.
|
47
|
+
|
48
|
+
./script/plugin install git://github.com/jqr/stale_object_destroyer.git
|
49
|
+
|
50
|
+
Prefer gems? Add this to your environment.rb and run the following command.
|
51
|
+
|
52
|
+
config.gem 'jqr-stale_object_destroyer', :lib => 'stale_object_destroyer', :source => 'http://gems.github.com'
|
53
|
+
|
54
|
+
$ rake gems:install
|
55
|
+
|
56
|
+
|
57
|
+
Homepage:: http://github.com/jqr/versionable/tree/master
|
58
|
+
License:: Copyright (c) 2008 Elijah Miller <mailto:elijah.miller@gmail.com> and Kristopher Chambers <mailto:kristopher.chambers@gmail.com, released under the MIT license.
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec/rake/spectask'
|
2
|
+
|
3
|
+
require 'echoe'
|
4
|
+
Echoe.new 'stale_object_destroyer' do |p|
|
5
|
+
p.description = "An easy way to handle stale object errors in Rails by retrying the entire request."
|
6
|
+
p.url = "http://github.com/jqr/stale_object_destroyer"
|
7
|
+
p.author = "Elijah Miller"
|
8
|
+
p.email = "elijah.miller@gmail.com"
|
9
|
+
p.retain_gemspec = true
|
10
|
+
p.need_tar_gz = false
|
11
|
+
p.extra_deps = [
|
12
|
+
]
|
13
|
+
end
|
14
|
+
|
15
|
+
desc 'Default: run specs'
|
16
|
+
task :default => :spec
|
17
|
+
Spec::Rake::SpecTask.new do |t|
|
18
|
+
t.spec_files = FileList["spec/**/*_spec.rb"]
|
19
|
+
end
|
20
|
+
|
21
|
+
task :test => :spec
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'stale_object_destroyer'
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class ActionController::CgiRequest
|
2
|
+
attr_accessor :attempt, :last_attempt
|
3
|
+
|
4
|
+
def last_attempt?
|
5
|
+
last_attempt
|
6
|
+
end
|
7
|
+
|
8
|
+
def reraise_stale_object_errors(exception)
|
9
|
+
if exception.is_a?(ActiveRecord::StaleObjectError) && !last_attempt?
|
10
|
+
raise exception
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class ActionController::Base
|
16
|
+
class << self
|
17
|
+
def process_with_destroyer(request, response)
|
18
|
+
max = 5
|
19
|
+
(1..max).each do |attempt|
|
20
|
+
begin
|
21
|
+
request.attempt = attempt
|
22
|
+
request.last_attempt = attempt == max
|
23
|
+
|
24
|
+
return process_without_destroyer(request, response)
|
25
|
+
rescue ActiveRecord::StaleObjectError => err
|
26
|
+
logger.error "[StaleObjectDestroyer] #{err.message} on attempt #{attempt}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
alias_method_chain :process, :destroyer
|
32
|
+
end
|
33
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{stale_object_destroyer}
|
5
|
+
s.version = "0.0.1"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Elijah Miller"]
|
9
|
+
s.date = %q{2009-02-11}
|
10
|
+
s.description = %q{An easy way to handle stale object errors in Rails by retrying the entire request.}
|
11
|
+
s.email = %q{elijah.miller@gmail.com}
|
12
|
+
s.extra_rdoc_files = ["CHANGELOG", "lib/stale_object_destroyer.rb", "README.rdoc"]
|
13
|
+
s.files = ["CHANGELOG", "init.rb", "lib/stale_object_destroyer.rb", "Manifest", "Rakefile", "README.rdoc", "spec/spec_helper.rb", "stale_object_destroyer.gemspec"]
|
14
|
+
s.has_rdoc = true
|
15
|
+
s.homepage = %q{http://github.com/jqr/stale_object_destroyer}
|
16
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Stale_object_destroyer", "--main", "README.rdoc"]
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
s.rubyforge_project = %q{stale_object_destroyer}
|
19
|
+
s.rubygems_version = %q{1.3.1}
|
20
|
+
s.summary = %q{An easy way to handle stale object errors in Rails by retrying the entire request.}
|
21
|
+
|
22
|
+
if s.respond_to? :specification_version then
|
23
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
24
|
+
s.specification_version = 2
|
25
|
+
|
26
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
27
|
+
s.add_development_dependency(%q<echoe>, [">= 0"])
|
28
|
+
else
|
29
|
+
s.add_dependency(%q<echoe>, [">= 0"])
|
30
|
+
end
|
31
|
+
else
|
32
|
+
s.add_dependency(%q<echoe>, [">= 0"])
|
33
|
+
end
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jqr-stale_object_destroyer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Elijah Miller
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-02-11 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: echoe
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: "0"
|
23
|
+
version:
|
24
|
+
description: An easy way to handle stale object errors in Rails by retrying the entire request.
|
25
|
+
email: elijah.miller@gmail.com
|
26
|
+
executables: []
|
27
|
+
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files:
|
31
|
+
- CHANGELOG
|
32
|
+
- lib/stale_object_destroyer.rb
|
33
|
+
- README.rdoc
|
34
|
+
files:
|
35
|
+
- CHANGELOG
|
36
|
+
- init.rb
|
37
|
+
- lib/stale_object_destroyer.rb
|
38
|
+
- Manifest
|
39
|
+
- Rakefile
|
40
|
+
- README.rdoc
|
41
|
+
- spec/spec_helper.rb
|
42
|
+
- stale_object_destroyer.gemspec
|
43
|
+
has_rdoc: true
|
44
|
+
homepage: http://github.com/jqr/stale_object_destroyer
|
45
|
+
post_install_message:
|
46
|
+
rdoc_options:
|
47
|
+
- --line-numbers
|
48
|
+
- --inline-source
|
49
|
+
- --title
|
50
|
+
- Stale_object_destroyer
|
51
|
+
- --main
|
52
|
+
- README.rdoc
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: "0"
|
60
|
+
version:
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: "1.2"
|
66
|
+
version:
|
67
|
+
requirements: []
|
68
|
+
|
69
|
+
rubyforge_project: stale_object_destroyer
|
70
|
+
rubygems_version: 1.2.0
|
71
|
+
signing_key:
|
72
|
+
specification_version: 2
|
73
|
+
summary: An easy way to handle stale object errors in Rails by retrying the entire request.
|
74
|
+
test_files: []
|
75
|
+
|