double_entry 0.7.2 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e815a7e5aabf260a4697a11f7685d362c017cdfb
|
4
|
+
data.tar.gz: 416041a85f823156b3211c58edcb751a07ea60d1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0b36f7c934a87f36ec0250d360b043e4a98c033bd74289eaa9cade1e120f35fa438376629bb8d099de122481f28411ecc4a6890641646e56ba49afad52d99312
|
7
|
+
data.tar.gz: 4c8a843ba84218611d2545b161f58cddbb03617c94564027f02e85957e6754d299d5381f37527e5cc0f7b3e58e05a4821fb27c82883b750fe139db61e901cf0c
|
@@ -1,4 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
require "active_support/notifications"
|
3
|
+
|
2
4
|
module ActiveRecord
|
3
5
|
|
4
6
|
# These methods are available as class methods on ActiveRecord::Base.
|
@@ -21,6 +23,8 @@ module ActiveRecord
|
|
21
23
|
yield
|
22
24
|
rescue ActiveRecord::StatementInvalid => exception
|
23
25
|
if exception.message =~ /deadlock/i || exception.message =~ /database is locked/i
|
26
|
+
ActiveSupport::Notifications.publish("deadlock_restart.active_record", :exception => exception)
|
27
|
+
|
24
28
|
raise ActiveRecord::RestartTransaction
|
25
29
|
else
|
26
30
|
raise
|
@@ -49,6 +53,8 @@ module ActiveRecord
|
|
49
53
|
yield
|
50
54
|
rescue ActiveRecord::StatementInvalid, ActiveRecord::RecordNotUnique => exception
|
51
55
|
if exception.message =~ /duplicate/i || exception.message =~ /ConstraintException/
|
56
|
+
ActiveSupport::Notifications.publish("duplicate_ignore.active_record", :exception => exception)
|
57
|
+
|
52
58
|
# Just ignore it...someone else has already created the record.
|
53
59
|
else
|
54
60
|
raise
|
@@ -66,6 +72,8 @@ module ActiveRecord
|
|
66
72
|
if exception.message =~ /deadlock/i || exception.message =~ /database is locked/i
|
67
73
|
# Somebody else is in the midst of creating the record. We'd better
|
68
74
|
# retry, so we ensure they're done before we move on.
|
75
|
+
ActiveSupport::Notifications.publish("deadlock_retry.active_record", :exception => exception)
|
76
|
+
|
69
77
|
retry
|
70
78
|
else
|
71
79
|
raise
|
@@ -80,4 +88,5 @@ module ActiveRecord
|
|
80
88
|
|
81
89
|
end
|
82
90
|
|
91
|
+
|
83
92
|
ActiveRecord::Base.extend(ActiveRecord::LockingExtensions)
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "active_support/log_subscriber"
|
3
|
+
|
4
|
+
module ActiveRecord
|
5
|
+
module LockingExtensions
|
6
|
+
class LogSubscriber < ActiveSupport::LogSubscriber
|
7
|
+
def deadlock_restart(event)
|
8
|
+
info "Deadlock causing restart"
|
9
|
+
debug event[:exception]
|
10
|
+
end
|
11
|
+
|
12
|
+
def deadlock_retry(event)
|
13
|
+
info "Deadlock causing retry"
|
14
|
+
debug event[:exception]
|
15
|
+
end
|
16
|
+
|
17
|
+
def duplicate_ignore(event)
|
18
|
+
info "Duplicate ignored"
|
19
|
+
debug event[:exception]
|
20
|
+
end
|
21
|
+
|
22
|
+
def logger
|
23
|
+
ActiveRecord::Base.logger
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
ActiveRecord::LockingExtensions::LogSubscriber.attach_to :active_record
|
data/lib/double_entry.rb
CHANGED
data/lib/double_entry/version.rb
CHANGED
@@ -17,15 +17,34 @@ describe ActiveRecord::LockingExtensions do
|
|
17
17
|
end
|
18
18
|
|
19
19
|
context "#with_restart_on_deadlock" do
|
20
|
-
|
21
|
-
it "
|
22
|
-
expect { User.with_restart_on_deadlock { raise
|
20
|
+
shared_examples "abstract adapter" do
|
21
|
+
it "raises a ActiveRecord::RestartTransaction error if a deadlock occurs" do
|
22
|
+
expect { User.with_restart_on_deadlock { raise exception } }.to raise_error(ActiveRecord::RestartTransaction)
|
23
23
|
end
|
24
24
|
|
25
|
-
it "
|
26
|
-
expect
|
25
|
+
it "publishes a notification" do
|
26
|
+
expect(ActiveSupport::Notifications).to receive(:publish).with("deadlock_restart.active_record", hash_including(:exception => exception))
|
27
|
+
expect { User.with_restart_on_deadlock { raise exception } }.to raise_error
|
27
28
|
end
|
28
29
|
end
|
30
|
+
|
31
|
+
context "mysql" do
|
32
|
+
let(:exception) { MYSQL_DEADLOCK }
|
33
|
+
|
34
|
+
it_behaves_like "abstract adapter"
|
35
|
+
end
|
36
|
+
|
37
|
+
context "postgres" do
|
38
|
+
let(:exception) { PG_DEADLOCK }
|
39
|
+
|
40
|
+
it_behaves_like "abstract adapter"
|
41
|
+
end
|
42
|
+
|
43
|
+
context "sqlite" do
|
44
|
+
let(:exception) { SQLITE3_LOCK }
|
45
|
+
|
46
|
+
it_behaves_like "abstract adapter"
|
47
|
+
end
|
29
48
|
end
|
30
49
|
|
31
50
|
context "#create_ignoring_duplicates" do
|
@@ -36,27 +55,49 @@ describe ActiveRecord::LockingExtensions do
|
|
36
55
|
expect { User.create_ignoring_duplicates! :username => "keith" }.to_not raise_error
|
37
56
|
end
|
38
57
|
|
39
|
-
|
40
|
-
|
41
|
-
expect(User).to receive(:create!).ordered.and_raise(MYSQL_DEADLOCK)
|
42
|
-
expect(User).to receive(:create!).ordered.and_return(true)
|
58
|
+
it "publishes a notification when a duplicate is encountered" do
|
59
|
+
User.make! :username => "keith"
|
43
60
|
|
44
|
-
|
45
|
-
end
|
61
|
+
expect(ActiveSupport::Notifications).to receive(:publish).with("duplicate_ignore.active_record", hash_including(:exception => kind_of(ActiveRecord::RecordNotUnique)))
|
46
62
|
|
47
|
-
|
48
|
-
|
63
|
+
expect { User.create_ignoring_duplicates! :username => "keith" }.to_not raise_error
|
64
|
+
end
|
65
|
+
|
66
|
+
shared_examples "abstract adapter" do
|
67
|
+
it "retries the creation if a deadlock error is raised from the database" do
|
68
|
+
expect(User).to receive(:create!).ordered.and_raise(exception)
|
49
69
|
expect(User).to receive(:create!).ordered.and_return(true)
|
50
70
|
|
51
71
|
expect { User.create_ignoring_duplicates! }.to_not raise_error
|
52
72
|
end
|
53
73
|
|
54
|
-
it "
|
55
|
-
expect(User).to receive(:create!).ordered.and_raise(
|
74
|
+
it "publishes a notification on each retry" do
|
75
|
+
expect(User).to receive(:create!).ordered.and_raise(exception)
|
76
|
+
expect(User).to receive(:create!).ordered.and_raise(exception)
|
56
77
|
expect(User).to receive(:create!).ordered.and_return(true)
|
57
78
|
|
79
|
+
expect(ActiveSupport::Notifications).to receive(:publish).with("deadlock_retry.active_record", hash_including(:exception => exception)).twice
|
80
|
+
|
58
81
|
expect { User.create_ignoring_duplicates! }.to_not raise_error
|
59
82
|
end
|
60
83
|
end
|
84
|
+
|
85
|
+
context "mysql" do
|
86
|
+
let(:exception) { MYSQL_DEADLOCK }
|
87
|
+
|
88
|
+
it_behaves_like "abstract adapter"
|
89
|
+
end
|
90
|
+
|
91
|
+
context "postgres" do
|
92
|
+
let(:exception) { PG_DEADLOCK }
|
93
|
+
|
94
|
+
it_behaves_like "abstract adapter"
|
95
|
+
end
|
96
|
+
|
97
|
+
context "sqlite" do
|
98
|
+
let(:exception) { SQLITE3_LOCK }
|
99
|
+
|
100
|
+
it_behaves_like "abstract adapter"
|
101
|
+
end
|
61
102
|
end
|
62
103
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: double_entry
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Anthony Sellitti
|
@@ -15,7 +15,7 @@ authors:
|
|
15
15
|
autorequire:
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
|
-
date: 2014-11-
|
18
|
+
date: 2014-11-19 00:00:00.000000000 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: money
|
@@ -237,6 +237,7 @@ files:
|
|
237
237
|
- Rakefile
|
238
238
|
- double_entry.gemspec
|
239
239
|
- lib/active_record/locking_extensions.rb
|
240
|
+
- lib/active_record/locking_extensions/log_subscriber.rb
|
240
241
|
- lib/double_entry.rb
|
241
242
|
- lib/double_entry/account.rb
|
242
243
|
- lib/double_entry/account_balance.rb
|