retryable_record 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.travis.yml +1 -0
- data/README.rdoc +43 -4
- data/lib/retryable_record/import.rb +19 -0
- data/lib/retryable_record/version.rb +1 -1
- data/lib/retryable_record.rb +18 -4
- data/retryable_record.gemspec +1 -0
- data/test/helper.rb +0 -6
- data/test/retryable_record_import_test.rb +23 -0
- data/test/retryable_record_test.rb +27 -11
- metadata +28 -4
- data/test.watchr +0 -15
data/.travis.yml
CHANGED
data/README.rdoc
CHANGED
@@ -2,14 +2,37 @@
|
|
2
2
|
|
3
3
|
Retries an operation on an ActiveRecord until no StaleObjectError is being raised.
|
4
4
|
|
5
|
+
{<img src="https://secure.travis-ci.org/neopoly/retryable_record.png?branch=master" alt="Build Status" />}[http://travis-ci.org/neopoly/retryable_record] {<img src="https://badge.fury.io/rb/retryable_record.png" alt="Gem Version" />}[http://badge.fury.io/rb/retryable_record] {<img src="https://codeclimate.com/github/neopoly/retryable_record.png" />}[https://codeclimate.com/github/neopoly/retryable_record]
|
6
|
+
|
5
7
|
Gem[https://rubygems.org/gems/retryable_record] |
|
6
8
|
Source[http://github.com/neopoly/retryable_record] |
|
7
|
-
|
8
|
-
{<img src="https://secure.travis-ci.org/neopoly/retryable_record.png?branch=master" alt="Build Status" />}[http://travis-ci.org/neopoly/retryable_record]
|
9
|
+
Documentation[http://rdoc.info/github/neopoly/retryable_record/master/frames]
|
9
10
|
|
10
11
|
|
11
12
|
== Usage
|
12
13
|
|
14
|
+
You can use +retryable_record+ in 3 different ways:
|
15
|
+
|
16
|
+
=== Module function
|
17
|
+
|
18
|
+
require 'retryable_record'
|
19
|
+
|
20
|
+
RetryableRecord.retry(user) do
|
21
|
+
user.username = "foo"
|
22
|
+
user.save!
|
23
|
+
end
|
24
|
+
|
25
|
+
=== Kernel import
|
26
|
+
|
27
|
+
require 'retryable_record/import'
|
28
|
+
|
29
|
+
RetryableRecord(user) do
|
30
|
+
user.username = "foo"
|
31
|
+
user.save!
|
32
|
+
end
|
33
|
+
|
34
|
+
=== Module inclusion
|
35
|
+
|
13
36
|
require 'retryable_record'
|
14
37
|
|
15
38
|
class User < ActiveRecord::Base
|
@@ -23,12 +46,28 @@ RDoc[http://rdoc.info/projects/neopoly/retryable_record] |
|
|
23
46
|
user.save!
|
24
47
|
end
|
25
48
|
|
49
|
+
== Optimistic locking (lock_version column)
|
50
|
+
|
51
|
+
ActiveRecord migration needs to support optimistic locking. See http://api.rubyonrails.org/classes/ActiveRecord/Locking/Optimistic.html
|
52
|
+
|
53
|
+
class CreateUsers < ActiveRecord::Migration
|
54
|
+
def change
|
55
|
+
create_table :users do |t|
|
56
|
+
t.string :name
|
57
|
+
t.integer :lock_version
|
58
|
+
|
59
|
+
t.timestamps
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
|
26
65
|
== Credits
|
27
66
|
|
28
67
|
Inspired by
|
29
|
-
* http://vision-media.ca/resources/ruby/better-ruby-retryable-method
|
30
68
|
* http://blog.codefront.net/2008/01/14/retrying-code-blocks-in-ruby-on-exceptions-whatever/
|
31
|
-
* http://github.com/
|
69
|
+
* http://github.com/nfedyashev/retryable
|
70
|
+
* http://vision-media.ca/resources/ruby/better-ruby-retryable-method (broken)
|
32
71
|
|
33
72
|
== TODO
|
34
73
|
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'retryable_record'
|
2
|
+
|
3
|
+
module Kernel
|
4
|
+
# Retryable operations on an ActiveRecord +record+.
|
5
|
+
#
|
6
|
+
# == Example
|
7
|
+
#
|
8
|
+
# require 'retryable_record/import'
|
9
|
+
#
|
10
|
+
# RetryableRecord(user) do
|
11
|
+
# user.username = "foo"
|
12
|
+
# user.save!
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# See RetryableRecord#retry
|
16
|
+
def RetryableRecord(record, &block)
|
17
|
+
RetryableRecord.retry(record, &block)
|
18
|
+
end
|
19
|
+
end
|
data/lib/retryable_record.rb
CHANGED
@@ -3,7 +3,7 @@ require 'active_record/base'
|
|
3
3
|
|
4
4
|
# Retries an operation on an ActiveRecord until no StaleObjectError is being raised.
|
5
5
|
#
|
6
|
-
#
|
6
|
+
# == Example
|
7
7
|
#
|
8
8
|
# class User < ActiveRecord::Base
|
9
9
|
# include RetryableRecord
|
@@ -16,12 +16,26 @@ require 'active_record/base'
|
|
16
16
|
# user.save!
|
17
17
|
# end
|
18
18
|
#
|
19
|
-
# @yield Operation that should be retried on failure ActiveRecord::StaleObjectError.
|
20
19
|
module RetryableRecord
|
21
|
-
|
20
|
+
# Retryable operations on an ActiveRecord +record+.
|
21
|
+
#
|
22
|
+
# == Example
|
23
|
+
#
|
24
|
+
# RetryableRecord.retry(user) do
|
25
|
+
# user.username = "foo"
|
26
|
+
# user.save!
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
def retry(record)
|
22
30
|
yield
|
23
31
|
rescue ActiveRecord::StaleObjectError
|
24
|
-
reload
|
32
|
+
record.reload
|
25
33
|
retry
|
26
34
|
end
|
35
|
+
module_function :retry
|
36
|
+
|
37
|
+
# Retries operations on an ActiveRecord.
|
38
|
+
def retryable(&block)
|
39
|
+
RetryableRecord.retry(self, &block)
|
40
|
+
end
|
27
41
|
end
|
data/retryable_record.gemspec
CHANGED
data/test/helper.rb
CHANGED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'retryable_record/import'
|
3
|
+
|
4
|
+
class RetryableRecordImportTest < Spec
|
5
|
+
let(:retries) { 0 }
|
6
|
+
let(:record) { FakeRecord.new(retries) }
|
7
|
+
|
8
|
+
describe :RetryableRecord do
|
9
|
+
before do
|
10
|
+
RetryableRecord(record) do
|
11
|
+
record.concurrent_modification!
|
12
|
+
record.save!
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:retries) { 0 }
|
17
|
+
|
18
|
+
it "saves and does not retry" do
|
19
|
+
assert_equal 0, record.counter[:reload]
|
20
|
+
assert_equal 1, record.counter[:save]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -4,33 +4,33 @@ class RetryableRecordTest < Spec
|
|
4
4
|
let(:retries) { 0 }
|
5
5
|
let(:record) { FakeRecord.new(retries) }
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
record
|
10
|
-
|
7
|
+
describe :retry do
|
8
|
+
before do
|
9
|
+
RetryableRecord.retry(record) do
|
10
|
+
record.concurrent_modification!
|
11
|
+
record.save!
|
12
|
+
end
|
11
13
|
end
|
12
|
-
end
|
13
14
|
|
14
|
-
|
15
|
-
context "without retry" do
|
15
|
+
describe "without retry" do
|
16
16
|
let(:retries) { 0 }
|
17
17
|
|
18
|
-
|
18
|
+
it "saves and does not retry" do
|
19
19
|
assert_equal 0, record.counter[:reload]
|
20
20
|
assert_equal 1, record.counter[:save]
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
|
24
|
+
describe "with retry once" do
|
25
25
|
let(:retries) { 5 }
|
26
26
|
|
27
|
-
|
27
|
+
it "saves and reloads 5 times" do
|
28
28
|
assert_equal 5, record.counter[:reload]
|
29
29
|
assert_equal 1, record.counter[:save]
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
|
33
|
+
it "does not rescue other errors" do
|
34
34
|
assert_raises RuntimeError do
|
35
35
|
record.retryable do
|
36
36
|
raise "foo"
|
@@ -41,4 +41,20 @@ class RetryableRecordTest < Spec
|
|
41
41
|
assert_equal 1, record.counter[:save]
|
42
42
|
end
|
43
43
|
end
|
44
|
+
|
45
|
+
describe :retryable do
|
46
|
+
before do
|
47
|
+
record.retryable do
|
48
|
+
record.concurrent_modification!
|
49
|
+
record.save!
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
let(:retries) { 0 }
|
54
|
+
|
55
|
+
it "saves and does not retry" do
|
56
|
+
assert_equal 0, record.counter[:reload]
|
57
|
+
assert_equal 1, record.counter[:save]
|
58
|
+
end
|
59
|
+
end
|
44
60
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: retryable_record
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-05-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -43,6 +43,22 @@ dependencies:
|
|
43
43
|
- - ! '>='
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rdoc
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
46
62
|
- !ruby/object:Gem::Dependency
|
47
63
|
name: minitest
|
48
64
|
requirement: !ruby/object:Gem::Requirement
|
@@ -77,10 +93,11 @@ files:
|
|
77
93
|
- Rakefile
|
78
94
|
- VERSION
|
79
95
|
- lib/retryable_record.rb
|
96
|
+
- lib/retryable_record/import.rb
|
80
97
|
- lib/retryable_record/version.rb
|
81
98
|
- retryable_record.gemspec
|
82
|
-
- test.watchr
|
83
99
|
- test/helper.rb
|
100
|
+
- test/retryable_record_import_test.rb
|
84
101
|
- test/retryable_record_test.rb
|
85
102
|
homepage: https://github.com/neopoly/retryable_record
|
86
103
|
licenses: []
|
@@ -94,19 +111,26 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
94
111
|
- - ! '>='
|
95
112
|
- !ruby/object:Gem::Version
|
96
113
|
version: '0'
|
114
|
+
segments:
|
115
|
+
- 0
|
116
|
+
hash: -864916261665633026
|
97
117
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
98
118
|
none: false
|
99
119
|
requirements:
|
100
120
|
- - ! '>='
|
101
121
|
- !ruby/object:Gem::Version
|
102
122
|
version: '0'
|
123
|
+
segments:
|
124
|
+
- 0
|
125
|
+
hash: -864916261665633026
|
103
126
|
requirements: []
|
104
127
|
rubyforge_project:
|
105
|
-
rubygems_version: 1.8.
|
128
|
+
rubygems_version: 1.8.25
|
106
129
|
signing_key:
|
107
130
|
specification_version: 3
|
108
131
|
summary: Retries an operation on an ActiveRecord until no StaleObjectError is being
|
109
132
|
raised.
|
110
133
|
test_files:
|
111
134
|
- test/helper.rb
|
135
|
+
- test/retryable_record_import_test.rb
|
112
136
|
- test/retryable_record_test.rb
|
data/test.watchr
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
#!/usr/bin/env watchr
|
2
|
-
|
3
|
-
begin
|
4
|
-
require File.join(ENV["HOME"], ".watchr.test.rb")
|
5
|
-
rescue LoadError
|
6
|
-
warn "Unable to load #{File.join(ENV["HOME"], ".watchr.test.rb")}"
|
7
|
-
warn "You might try this: http://gist.github.com/raw/273574/8804dff44b104e9b8706826dc8882ed985b4fd13/.watchr.test.rb"
|
8
|
-
exit
|
9
|
-
end
|
10
|
-
|
11
|
-
run_tests
|
12
|
-
|
13
|
-
watch('test/.*_test\.rb') { |md| run md[0] }
|
14
|
-
watch('lib/(.*)\.rb') { |md| run "test/#{underscore(md[1])}_test.rb" }
|
15
|
-
watch('test/teststrap.rb') { run_tests }
|