double_entry 0.7.2 → 0.8.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.
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
|