openstax_transaction_retry 1.2.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/lib/open_stax_transaction_retry/version.rb +1 -1
- data/open_stax_transaction_retry.gemspec +4 -5
- metadata +9 -21
- data/d +0 -1
- data/test/db/all.rb +0 -6
- data/test/db/db.rb +0 -37
- data/test/db/migrations.rb +0 -19
- data/test/db/queued_job.rb +0 -4
- data/test/integration/active_record/base/transaction_with_retry_test.rb +0 -209
- data/test/library_setup.rb +0 -27
- data/test/log/.gitkeep +0 -0
- data/test/test_console.rb +0 -14
- data/test/test_helper.rb +0 -14
- data/test/test_runner.rb +0 -6
- data/tests +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8454103b320f693e3cab50ae57dc9de433089328baa396405dc89b19d58cac14
|
4
|
+
data.tar.gz: 4d7404ecbfb74328d6d75052f1ef9bbd6732476021cfb40467dab5a2d27f90f4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8febebd64c85b5a9c25a875489bafb728a246549a8784895c49320ecdf15163bf3e703eba6050888df496fb7d27a3cf97a822cd57653e739fdf1e3bb5be74a63
|
7
|
+
data.tar.gz: 1dcd1c4e8c8f71b567d0acc08a24d72f56111a5d40a0b7d1ec41346fe53240bf71bdc6229231ceb744c07640217a18f74ce2bd5451d9762a73f84ddc2763d010
|
data/.rubocop.yml
CHANGED
@@ -11,13 +11,12 @@ Gem::Specification.new do |s|
|
|
11
11
|
s.homepage = 'https://github.com/openstax/transaction_retry'
|
12
12
|
s.summary = 'Retries database transaction on deadlock and transaction serialization errors. Supports MySQL, PostgreSQL and SQLite.'
|
13
13
|
s.description = 'Retries database transaction on deadlock and transaction serialization errors. Supports MySQL, PostgreSQL and SQLite (as long as you are using new drivers mysql2, pg, sqlite3).'
|
14
|
-
s.required_ruby_version = '>=
|
14
|
+
s.required_ruby_version = '>= 3.0'
|
15
15
|
|
16
|
-
s.files = `git ls-files`.split("\
|
17
|
-
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
16
|
+
s.files = `git ls-files -z`.split("\x0").reject { |f| f == 'd' || f.start_with?('test') }
|
18
17
|
s.require_paths = ['lib']
|
19
18
|
|
20
|
-
s.
|
21
|
-
s.
|
19
|
+
s.add_dependency 'activerecord', '>= 6'
|
20
|
+
s.add_dependency 'openstax_transaction_isolation', '>= 2'
|
22
21
|
s.metadata['rubygems_mfa_required'] = 'true'
|
23
22
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: openstax_transaction_retry
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nathan Stitt
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2025-01-02 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activerecord
|
@@ -18,28 +18,28 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - ">="
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: '
|
21
|
+
version: '6'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
requirements:
|
26
26
|
- - ">="
|
27
27
|
- !ruby/object:Gem::Version
|
28
|
-
version: '
|
28
|
+
version: '6'
|
29
29
|
- !ruby/object:Gem::Dependency
|
30
|
-
name:
|
30
|
+
name: openstax_transaction_isolation
|
31
31
|
requirement: !ruby/object:Gem::Requirement
|
32
32
|
requirements:
|
33
33
|
- - ">="
|
34
34
|
- !ruby/object:Gem::Version
|
35
|
-
version:
|
35
|
+
version: '2'
|
36
36
|
type: :runtime
|
37
37
|
prerelease: false
|
38
38
|
version_requirements: !ruby/object:Gem::Requirement
|
39
39
|
requirements:
|
40
40
|
- - ">="
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version:
|
42
|
+
version: '2'
|
43
43
|
description: Retries database transaction on deadlock and transaction serialization
|
44
44
|
errors. Supports MySQL, PostgreSQL and SQLite (as long as you are using new drivers
|
45
45
|
mysql2, pg, sqlite3).
|
@@ -58,22 +58,10 @@ files:
|
|
58
58
|
- LICENSE
|
59
59
|
- README.md
|
60
60
|
- Rakefile
|
61
|
-
- d
|
62
61
|
- lib/open_stax_transaction_retry.rb
|
63
62
|
- lib/open_stax_transaction_retry/active_record/base.rb
|
64
63
|
- lib/open_stax_transaction_retry/version.rb
|
65
64
|
- open_stax_transaction_retry.gemspec
|
66
|
-
- test/db/all.rb
|
67
|
-
- test/db/db.rb
|
68
|
-
- test/db/migrations.rb
|
69
|
-
- test/db/queued_job.rb
|
70
|
-
- test/integration/active_record/base/transaction_with_retry_test.rb
|
71
|
-
- test/library_setup.rb
|
72
|
-
- test/log/.gitkeep
|
73
|
-
- test/test_console.rb
|
74
|
-
- test/test_helper.rb
|
75
|
-
- test/test_runner.rb
|
76
|
-
- tests
|
77
65
|
homepage: https://github.com/openstax/transaction_retry
|
78
66
|
licenses: []
|
79
67
|
metadata:
|
@@ -86,14 +74,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
86
74
|
requirements:
|
87
75
|
- - ">="
|
88
76
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
77
|
+
version: '3.0'
|
90
78
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
79
|
requirements:
|
92
80
|
- - ">="
|
93
81
|
- !ruby/object:Gem::Version
|
94
82
|
version: '0'
|
95
83
|
requirements: []
|
96
|
-
rubygems_version: 3.4.
|
84
|
+
rubygems_version: 3.4.6
|
97
85
|
signing_key:
|
98
86
|
specification_version: 4
|
99
87
|
summary: Retries database transaction on deadlock and transaction serialization errors.
|
data/test/db/all.rb
DELETED
data/test/db/db.rb
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'fileutils'
|
4
|
-
|
5
|
-
module OpenStaxTransactionRetry
|
6
|
-
module Test
|
7
|
-
module Db
|
8
|
-
def self.connect_to_mysql2
|
9
|
-
::ActiveRecord::Base.establish_connection(
|
10
|
-
adapter: 'mysql2',
|
11
|
-
database: 'transaction_retry_test',
|
12
|
-
username: ENV.fetch('DB_USERNAME'),
|
13
|
-
password: ENV.fetch('DB_PASSWORD', nil)
|
14
|
-
)
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.connect_to_postgresql
|
18
|
-
::ActiveRecord::Base.establish_connection(
|
19
|
-
adapter: 'postgresql',
|
20
|
-
host: ENV.fetch('DB_HOST', nil),
|
21
|
-
port: ENV.fetch('DB_PORT', nil),
|
22
|
-
database: ENV.fetch('DB_NAME', nil),
|
23
|
-
user: ENV.fetch('DB_USERNAME', nil),
|
24
|
-
password: ENV.fetch('DB_PASSWORD', nil)
|
25
|
-
)
|
26
|
-
end
|
27
|
-
|
28
|
-
def self.connect_to_sqlite3
|
29
|
-
ActiveRecord::Base.establish_connection(
|
30
|
-
adapter: 'sqlite3',
|
31
|
-
database: ':memory:',
|
32
|
-
verbosity: 'silent'
|
33
|
-
)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
data/test/db/migrations.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module OpenStaxTransactionRetry
|
4
|
-
module Test
|
5
|
-
module Migrations
|
6
|
-
def self.run!
|
7
|
-
c = ::ActiveRecord::Base.connection
|
8
|
-
|
9
|
-
# Queued Jobs
|
10
|
-
|
11
|
-
c.create_table 'queued_jobs', force: true do |t|
|
12
|
-
t.text 'job', null: false
|
13
|
-
t.integer 'status', default: 0, null: false
|
14
|
-
t.timestamps
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
data/test/db/queued_job.rb
DELETED
@@ -1,209 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'test_helper'
|
4
|
-
|
5
|
-
class TransactionWithRetryTest < Minitest::Test
|
6
|
-
class CustomError < StandardError
|
7
|
-
end
|
8
|
-
|
9
|
-
def setup
|
10
|
-
@original_max_retries = OpenStaxTransactionRetry.max_retries
|
11
|
-
@original_wait_times = OpenStaxTransactionRetry.wait_times
|
12
|
-
@original_retry_on = OpenStaxTransactionRetry.retry_on
|
13
|
-
@original_before_retry = OpenStaxTransactionRetry.before_retry
|
14
|
-
end
|
15
|
-
|
16
|
-
def teardown
|
17
|
-
OpenStaxTransactionRetry.max_retries = @original_max_retries
|
18
|
-
OpenStaxTransactionRetry.wait_times = @original_wait_times
|
19
|
-
OpenStaxTransactionRetry.retry_on = @original_retry_on
|
20
|
-
OpenStaxTransactionRetry.before_retry = @original_before_retry
|
21
|
-
QueuedJob.delete_all
|
22
|
-
end
|
23
|
-
|
24
|
-
def test_does_not_break_transaction
|
25
|
-
ActiveRecord::Base.transaction do
|
26
|
-
QueuedJob.create!(job: 'is fun!')
|
27
|
-
assert_equal(1, QueuedJob.count)
|
28
|
-
end
|
29
|
-
assert_equal(1, QueuedJob.count)
|
30
|
-
QueuedJob.first.destroy
|
31
|
-
end
|
32
|
-
|
33
|
-
def test_does_not_break_transaction_rollback
|
34
|
-
ActiveRecord::Base.transaction do
|
35
|
-
QueuedJob.create!(job: 'gives money!')
|
36
|
-
raise ActiveRecord::Rollback
|
37
|
-
end
|
38
|
-
assert_equal(0, QueuedJob.count)
|
39
|
-
end
|
40
|
-
|
41
|
-
def test_retries_transaction_on_transaction_isolation_conflict
|
42
|
-
first_run = true
|
43
|
-
|
44
|
-
ActiveRecord::Base.transaction do
|
45
|
-
if first_run
|
46
|
-
first_run = false
|
47
|
-
message = 'Deadlock found when trying to get lock'
|
48
|
-
raise ActiveRecord::TransactionIsolationConflict, message
|
49
|
-
end
|
50
|
-
QueuedJob.create!(job: 'is cool!')
|
51
|
-
end
|
52
|
-
assert_equal(1, QueuedJob.count)
|
53
|
-
|
54
|
-
QueuedJob.first.destroy
|
55
|
-
end
|
56
|
-
|
57
|
-
def test_does_not_retry_on_unknown_error
|
58
|
-
first_run = true
|
59
|
-
|
60
|
-
assert_raises(CustomError) do
|
61
|
-
ActiveRecord::Base.transaction do
|
62
|
-
if first_run
|
63
|
-
first_run = false
|
64
|
-
raise CustomError, 'random error'
|
65
|
-
end
|
66
|
-
QueuedJob.create!(job: 'is cool!')
|
67
|
-
end
|
68
|
-
end
|
69
|
-
assert_equal(0, QueuedJob.count)
|
70
|
-
end
|
71
|
-
|
72
|
-
def test_retries_on_custom_error
|
73
|
-
first_run = true
|
74
|
-
ActiveRecord::Base.transaction(retry_on: CustomError) do
|
75
|
-
if first_run
|
76
|
-
first_run = false
|
77
|
-
raise CustomError, 'random error'
|
78
|
-
end
|
79
|
-
QueuedJob.create!(job: 'is cool!')
|
80
|
-
end
|
81
|
-
assert_equal(1, QueuedJob.count)
|
82
|
-
QueuedJob.first.destroy
|
83
|
-
end
|
84
|
-
|
85
|
-
def test_retries_on_configured_retry_on
|
86
|
-
OpenStaxTransactionRetry.retry_on = CustomError
|
87
|
-
first_run = true
|
88
|
-
ActiveRecord::Base.transaction do
|
89
|
-
if first_run
|
90
|
-
first_run = false
|
91
|
-
raise CustomError, 'random error'
|
92
|
-
end
|
93
|
-
QueuedJob.create!(job: 'is cool!')
|
94
|
-
end
|
95
|
-
assert_equal(1, QueuedJob.count)
|
96
|
-
QueuedJob.first.destroy
|
97
|
-
end
|
98
|
-
|
99
|
-
def test_retries_transaction_on_transaction_isolation_when_retry_on_set
|
100
|
-
OpenStaxTransactionRetry.retry_on = CustomError
|
101
|
-
first_run = true
|
102
|
-
ActiveRecord::Base.transaction do
|
103
|
-
if first_run
|
104
|
-
first_run = false
|
105
|
-
message = 'Deadlock found when trying to get lock'
|
106
|
-
raise ActiveRecord::TransactionIsolationConflict, message
|
107
|
-
end
|
108
|
-
QueuedJob.create!(job: 'is cool!')
|
109
|
-
end
|
110
|
-
assert_equal(1, QueuedJob.count)
|
111
|
-
QueuedJob.first.destroy
|
112
|
-
end
|
113
|
-
|
114
|
-
def test_does_not_retry_transaction_more_than_max_retries_times
|
115
|
-
OpenStaxTransactionRetry.max_retries = 1
|
116
|
-
run = 0
|
117
|
-
|
118
|
-
assert_raises(ActiveRecord::TransactionIsolationConflict) do
|
119
|
-
ActiveRecord::Base.transaction do
|
120
|
-
run += 1
|
121
|
-
message = 'Deadlock found when trying to get lock'
|
122
|
-
raise ActiveRecord::TransactionIsolationConflict, message
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
assert_equal(2, run) # normal run + one retry
|
127
|
-
|
128
|
-
OpenStaxTransactionRetry.max_retries = 3
|
129
|
-
|
130
|
-
run = 0
|
131
|
-
|
132
|
-
assert_raises(ActiveRecord::TransactionIsolationConflict) do
|
133
|
-
ActiveRecord::Base.transaction(max_retries: 1) do
|
134
|
-
run += 1
|
135
|
-
message = 'Deadlock found when trying to get lock'
|
136
|
-
raise ActiveRecord::TransactionIsolationConflict, message
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
assert_equal(2, run) # normal run + one retry
|
141
|
-
end
|
142
|
-
|
143
|
-
def test_does_not_retry_nested_transaction
|
144
|
-
first_try = true
|
145
|
-
|
146
|
-
ActiveRecord::Base.transaction do
|
147
|
-
assert_raises(ActiveRecord::TransactionIsolationConflict) do
|
148
|
-
ActiveRecord::Base.transaction(requires_new: true) do
|
149
|
-
if first_try
|
150
|
-
first_try = false
|
151
|
-
message = 'Deadlock found when trying to get lock'
|
152
|
-
raise ActiveRecord::TransactionIsolationConflict, message
|
153
|
-
end
|
154
|
-
QueuedJob.create!(job: 'is cool!')
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
assert_equal(0, QueuedJob.count)
|
160
|
-
end
|
161
|
-
|
162
|
-
def test_run_custom_lambda_before_retry
|
163
|
-
code_run = false
|
164
|
-
retry_id = nil
|
165
|
-
error_instance = nil
|
166
|
-
first_try = true
|
167
|
-
lambda_code = lambda do |retry_num, error|
|
168
|
-
code_run = true
|
169
|
-
retry_id = retry_num
|
170
|
-
error_instance = error
|
171
|
-
end
|
172
|
-
|
173
|
-
ActiveRecord::Base.transaction(before_retry: lambda_code) do
|
174
|
-
if first_try
|
175
|
-
first_try = false
|
176
|
-
raise ActiveRecord::TransactionIsolationConflict
|
177
|
-
end
|
178
|
-
QueuedJob.create!(job: 'is cool!')
|
179
|
-
end
|
180
|
-
assert_equal 1, QueuedJob.count
|
181
|
-
assert code_run
|
182
|
-
assert_equal 1, retry_id
|
183
|
-
assert_equal ActiveRecord::TransactionIsolationConflict, error_instance.class
|
184
|
-
end
|
185
|
-
|
186
|
-
def test_run_custom_global_lambda_before_retry
|
187
|
-
code_run = false
|
188
|
-
retry_id = nil
|
189
|
-
error_instance = nil
|
190
|
-
OpenStaxTransactionRetry.before_retry = lambda { |retry_num, error|
|
191
|
-
code_run = true
|
192
|
-
retry_id = retry_num
|
193
|
-
error_instance = error
|
194
|
-
}
|
195
|
-
first_try = true
|
196
|
-
|
197
|
-
ActiveRecord::Base.transaction do
|
198
|
-
if first_try
|
199
|
-
first_try = false
|
200
|
-
raise ActiveRecord::TransactionIsolationConflict
|
201
|
-
end
|
202
|
-
QueuedJob.create!(job: 'is cool!')
|
203
|
-
end
|
204
|
-
assert_equal 1, QueuedJob.count
|
205
|
-
assert code_run
|
206
|
-
assert_equal 1, retry_id
|
207
|
-
assert_equal ActiveRecord::TransactionIsolationConflict, error_instance.class
|
208
|
-
end
|
209
|
-
end
|
data/test/library_setup.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Prepares application to be tested (requires files, connects to db, resets schema and data, applies patches, etc.)
|
4
|
-
|
5
|
-
# Initialize database
|
6
|
-
require 'db/all'
|
7
|
-
|
8
|
-
case ENV.fetch('db', 'sqlite3')
|
9
|
-
when 'mysql2'
|
10
|
-
OpenStaxTransactionRetry::Test::Db.connect_to_mysql2
|
11
|
-
when 'postgresql'
|
12
|
-
OpenStaxTransactionRetry::Test::Db.connect_to_postgresql
|
13
|
-
when 'sqlite3'
|
14
|
-
OpenStaxTransactionRetry::Test::Db.connect_to_sqlite3
|
15
|
-
else
|
16
|
-
raise "Unknown database: #{ENV.fetch('db', nil)}"
|
17
|
-
end
|
18
|
-
|
19
|
-
require 'logger'
|
20
|
-
ActiveRecord::Base.logger = Logger.new(File.expand_path("#{File.dirname(__FILE__)}/log/test.log"))
|
21
|
-
|
22
|
-
OpenStaxTransactionRetry::Test::Migrations.run!
|
23
|
-
|
24
|
-
# Load the code that will be tested
|
25
|
-
require 'open_stax_transaction_retry'
|
26
|
-
|
27
|
-
OpenStaxTransactionRetry.apply_activerecord_patch
|
data/test/log/.gitkeep
DELETED
File without changes
|
data/test/test_console.rb
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Ensure that LOAD_PATH is the same as when running "rake test"; normally rake takes care of that
|
4
|
-
$LOAD_PATH << File.expand_path('.', File.dirname(__FILE__))
|
5
|
-
$LOAD_PATH << File.expand_path('./lib', File.dirname(__FILE__))
|
6
|
-
$LOAD_PATH << File.expand_path('./test', File.dirname(__FILE__))
|
7
|
-
|
8
|
-
# Boot the app
|
9
|
-
require_relative 'library_setup'
|
10
|
-
|
11
|
-
# Fire the console
|
12
|
-
require 'pry'
|
13
|
-
|
14
|
-
binding.pry # rubocop:disable Lint/Debugger
|
data/test/test_helper.rb
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Load test coverage tool (must be loaded before any code)
|
4
|
-
# require 'simplecov'
|
5
|
-
# SimpleCov.start do
|
6
|
-
# add_filter '/test/'
|
7
|
-
# add_filter '/config/'
|
8
|
-
# end
|
9
|
-
|
10
|
-
# Load and initialize the application to be tested
|
11
|
-
require 'library_setup'
|
12
|
-
|
13
|
-
# Load test frameworks
|
14
|
-
require 'minitest/autorun'
|
data/test/test_runner.rb
DELETED