openstax_transaction_retry 1.2.0 → 2.0.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 +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