sidekiq-transaction_guard 1.0.1 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +28 -4
- data/README.md +6 -4
- data/VERSION +1 -1
- data/lib/sidekiq/transaction_guard/database_cleaner.rb +7 -4
- data/lib/sidekiq/transaction_guard/middleware.rb +15 -11
- data/lib/sidekiq/transaction_guard.rb +25 -9
- data/lib/sidekiq-transaction_guard.rb +2 -0
- data/sidekiq-transaction_guard.gemspec +16 -24
- metadata +8 -78
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5f1c8f731c16ff8a3da91b3073be50dd1544a1b17a82521b60637baaa4643421
|
4
|
+
data.tar.gz: 711cd9daff96b69e24d54a8e21803bcf85bf64e60ab813ba168d943e7092f236
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ff23694280b688a5d0cdf7274408aa3640385dd4269814fb54421848c339f101b7dc865c7013dde0ff83ce6a9031810082155f3bfed727eaf9643a5b7cffdaa0
|
7
|
+
data.tar.gz: 36ad8e565e052c16e309fffa3f6e2b6fa715c8c694546b74b63d4aeee7f04224b68ebd193421a1f1f550fc8d02c8332507f0acf9583e1f074247d24eea60b3c4
|
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,31 @@
|
|
1
|
-
#
|
1
|
+
# Changelog
|
2
|
+
All notable changes to this project will be documented in this file.
|
2
3
|
|
3
|
-
|
4
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
4
6
|
|
5
|
-
|
7
|
+
## 1.0.3
|
6
8
|
|
7
|
-
|
9
|
+
### Changed
|
10
|
+
|
11
|
+
- Updated Middleware to include Sidekiq::ClientMiddleware for Sidekiq 7.0 compatibility
|
12
|
+
|
13
|
+
|
14
|
+
## 1.0.2
|
15
|
+
|
16
|
+
### Changed
|
17
|
+
|
18
|
+
- Updated database cleaner dependency to use database_cleaner-active_record instead of deprecated database_cleaner gem.
|
19
|
+
- Added YARD doc param and return types.
|
20
|
+
|
21
|
+
## 1.0.1
|
22
|
+
|
23
|
+
### Added
|
24
|
+
|
25
|
+
- Sidekiq 6.0 compatibility
|
26
|
+
|
27
|
+
## 1.0.0
|
28
|
+
|
29
|
+
### Added
|
30
|
+
|
31
|
+
- Initial release
|
data/README.md
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
-
# Sidekiq
|
1
|
+
# Sidekiq Transaction Guard
|
2
2
|
|
3
|
-
[![
|
4
|
-
[![
|
3
|
+
[![Continuous Integration](https://github.com/bdurand/sidekiq-transaction_guard/actions/workflows/continuous_integration.yml/badge.svg)](https://github.com/bdurand/sidekiq-transaction_guard/actions/workflows/continuous_integration.yml)
|
4
|
+
[![Regression Test](https://github.com/bdurand/sidekiq-transaction_guard/actions/workflows/regression_test.yml/badge.svg)](https://github.com/bdurand/sidekiq-transaction_guard/actions/workflows/regression_test.yml)
|
5
|
+
[![Ruby Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://github.com/testdouble/standard)
|
6
|
+
[![Gem Version](https://badge.fury.io/rb/sidekiq-transaction_guard.svg)](https://badge.fury.io/rb/sidekiq-transaction_guard)
|
5
7
|
|
6
8
|
You should never call a Sidekiq worker that relies on the state of the database from within a database transaction. You will end up with a race condition since the worker could kick off before the transaction is actually written to the database. This gem can be used to highlight where your code may be scheduling workers in an indeterminate state.
|
7
9
|
|
@@ -59,7 +61,7 @@ end
|
|
59
61
|
You can use this gem to add Sidekiq client middleware that will either warn you or raise an error when workers are scheduled inside of a database transaction. You can do this by simply adding this to your application's initialization code:
|
60
62
|
|
61
63
|
```ruby
|
62
|
-
require 'sidekiq/
|
64
|
+
require 'sidekiq/transaction_guard'
|
63
65
|
|
64
66
|
Sidekiq.configure_client do |config|
|
65
67
|
config.client_middleware do |chain|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0.
|
1
|
+
1.0.3
|
@@ -1,6 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "sidekiq/transaction_guard"
|
4
|
+
require "database_cleaner/active_record"
|
4
5
|
|
5
6
|
module Sidekiq
|
6
7
|
module TransactionGuard
|
@@ -16,8 +17,10 @@ module Sidekiq
|
|
16
17
|
|
17
18
|
# Wrap the `Sidekiq::TransactionGuard.testing` which sets up the data structures
|
18
19
|
# needed for custom counting of the transaction level within a test block.
|
20
|
+
#
|
21
|
+
# @return [Object] the return value of the block
|
19
22
|
def cleaning(&block)
|
20
|
-
Sidekiq::TransactionGuard.testing{ super(&block) }
|
23
|
+
Sidekiq::TransactionGuard.testing { super(&block) }
|
21
24
|
end
|
22
25
|
end
|
23
26
|
end
|
@@ -10,6 +10,10 @@ module Sidekiq
|
|
10
10
|
# the default behavior set in `Sidekiq::TransactionGuard.mode` and
|
11
11
|
# `Sidekiq::TransactionGuard.notify` respectively.
|
12
12
|
class Middleware
|
13
|
+
if Gem::Version.new(Sidekiq::VERSION) >= Gem::Version.new("7.0")
|
14
|
+
include Sidekiq::ClientMiddleware
|
15
|
+
end
|
16
|
+
|
13
17
|
def call(worker_class, job, queue, redis_pool)
|
14
18
|
# Check if we need to log this. Also, convert worker_class to its actual class
|
15
19
|
if in_transaction?
|
@@ -21,16 +25,16 @@ module Sidekiq
|
|
21
25
|
|
22
26
|
private
|
23
27
|
|
24
|
-
def worker_mode(
|
25
|
-
read_sidekiq_option(
|
28
|
+
def worker_mode(job)
|
29
|
+
read_sidekiq_option(job, :transaction_guard) || Sidekiq::TransactionGuard.mode
|
26
30
|
end
|
27
31
|
|
28
32
|
def in_transaction?
|
29
33
|
Sidekiq::TransactionGuard.in_transaction?
|
30
34
|
end
|
31
35
|
|
32
|
-
def notify_block(
|
33
|
-
handler = read_sidekiq_option(
|
36
|
+
def notify_block(job)
|
37
|
+
handler = read_sidekiq_option(job, :notify_in_transaction)
|
34
38
|
if handler
|
35
39
|
handler
|
36
40
|
elsif handler == false
|
@@ -40,13 +44,13 @@ module Sidekiq
|
|
40
44
|
end
|
41
45
|
end
|
42
46
|
|
43
|
-
def read_sidekiq_option(
|
44
|
-
options = worker_class.sidekiq_options_hash
|
45
|
-
|
47
|
+
def read_sidekiq_option(job, option_name)
|
48
|
+
# options = worker_class.sidekiq_options_hash
|
49
|
+
job[option_name.to_s]
|
46
50
|
end
|
47
51
|
|
48
52
|
def notify!(worker_class, job)
|
49
|
-
notify_handler = notify_block(
|
53
|
+
notify_handler = notify_block(job)
|
50
54
|
if notify_handler
|
51
55
|
begin
|
52
56
|
notify_handler.call(job)
|
@@ -54,14 +58,14 @@ module Sidekiq
|
|
54
58
|
if Sidekiq.logger
|
55
59
|
Sidekiq.logger.error(e)
|
56
60
|
else
|
57
|
-
|
61
|
+
$stderr.write("ERROR on Sidekiq::TransactionGuard notify block for #{worker_class}: #{e.inspect}\n")
|
58
62
|
end
|
59
63
|
end
|
60
64
|
end
|
61
65
|
end
|
62
66
|
|
63
67
|
def log_transaction(worker_class, job)
|
64
|
-
mode = worker_mode(
|
68
|
+
mode = worker_mode(job)
|
65
69
|
if mode != :disabled
|
66
70
|
message = "#{worker_class.name} was called from inside a database transaction"
|
67
71
|
if mode == :error
|
@@ -71,7 +75,7 @@ module Sidekiq
|
|
71
75
|
if logger
|
72
76
|
logger.warn(message)
|
73
77
|
else
|
74
|
-
|
78
|
+
$stderr.write("WARNING #{message}\n")
|
75
79
|
end
|
76
80
|
notify!(worker_class, job)
|
77
81
|
end
|
@@ -1,10 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require 'thread'
|
3
|
+
require "sidekiq"
|
4
|
+
require "set"
|
6
5
|
|
7
|
-
require_relative
|
6
|
+
require_relative "transaction_guard/middleware"
|
8
7
|
|
9
8
|
module Sidekiq
|
10
9
|
module TransactionGuard
|
@@ -26,6 +25,9 @@ module Sidekiq
|
|
26
25
|
# * :stderr - Log to STDERR
|
27
26
|
# * :error - Throw a `Sidekiq::TransactionGuard::InsideTransactionError`
|
28
27
|
# * :disabled - Allow workers inside of transactions
|
28
|
+
#
|
29
|
+
# @param mode [Symbol]
|
30
|
+
# @return [void]
|
29
31
|
def mode=(symbol)
|
30
32
|
if VALID_MODES.include?(symbol)
|
31
33
|
@mode = symbol
|
@@ -35,18 +37,22 @@ module Sidekiq
|
|
35
37
|
end
|
36
38
|
|
37
39
|
# Return the current mode.
|
38
|
-
|
39
|
-
|
40
|
-
|
40
|
+
#
|
41
|
+
# @return [Symbol]
|
42
|
+
attr_reader :mode
|
41
43
|
|
42
44
|
# Define the global notify block. This block will be called with a Sidekiq
|
43
45
|
# job hash for all jobs enqueued inside transactions if the mode is `:warn`
|
44
46
|
# or `:stderr`.
|
47
|
+
#
|
48
|
+
# @return [void]
|
45
49
|
def notify(&block)
|
46
50
|
@notify = block
|
47
51
|
end
|
48
52
|
|
49
53
|
# Return the block set as the notify handler with a call to `notify`.
|
54
|
+
#
|
55
|
+
# @return [Proc]
|
50
56
|
def notify_block
|
51
57
|
@notify
|
52
58
|
end
|
@@ -55,15 +61,20 @@ module Sidekiq
|
|
55
61
|
# being monitored for open transactions. You don't need to add `ActiveRecord::Base`
|
56
62
|
# or subclasses. Only the base class that establishes a new connection pool
|
57
63
|
# with a call to `establish_connection` needs to be added.
|
64
|
+
#
|
65
|
+
# @param connection_class [Class]
|
66
|
+
# @return [void]
|
58
67
|
def add_connection_class(connection_class)
|
59
|
-
@lock.synchronize{ @connection_classes << connection_class }
|
68
|
+
@lock.synchronize { @connection_classes << connection_class }
|
60
69
|
end
|
61
70
|
|
62
71
|
# Return true if any connection is currently inside of a transaction.
|
72
|
+
#
|
73
|
+
# @return [Boolean]
|
63
74
|
def in_transaction?
|
64
75
|
connection_classes = [ActiveRecord::Base]
|
65
76
|
unless @connection_classes.empty?
|
66
|
-
connection_classes.concat(@lock.synchronize{ @connection_classes.to_a })
|
77
|
+
connection_classes.concat(@lock.synchronize { @connection_classes.to_a })
|
67
78
|
end
|
68
79
|
connection_classes.any? do |connection_class|
|
69
80
|
connection_pool = connection_class.connection_pool
|
@@ -78,6 +89,8 @@ module Sidekiq
|
|
78
89
|
|
79
90
|
# This method call needs to be wrapped around tests that use transactional fixtures.
|
80
91
|
# It sets up data structures used to track the number of open transactions.
|
92
|
+
#
|
93
|
+
# @return [Object] the return value of the block
|
81
94
|
def testing(&block)
|
82
95
|
var = :sidekiq_rails_transaction_guard
|
83
96
|
save_val = Thread.current[var]
|
@@ -93,6 +106,9 @@ module Sidekiq
|
|
93
106
|
# class (see `add_connection_class` for more info). The current transaction level
|
94
107
|
# for that class' connection will be set as the zero point. This method can only
|
95
108
|
# be called inside a block wrapped with the `testing` method.
|
109
|
+
#
|
110
|
+
# @param connection_class [Class]
|
111
|
+
# @return [void]
|
96
112
|
def set_allowed_transaction_level(connection_class)
|
97
113
|
connection_counts = Thread.current[:sidekiq_rails_transaction_guard]
|
98
114
|
unless connection_counts
|
@@ -1,45 +1,37 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "lib/sidekiq/transaction_guard/version"
|
4
|
-
|
5
3
|
Gem::Specification.new do |spec|
|
6
|
-
spec.name
|
7
|
-
spec.version
|
8
|
-
spec.authors
|
9
|
-
spec.email
|
4
|
+
spec.name = "sidekiq-transaction_guard"
|
5
|
+
spec.version = File.read(File.expand_path("VERSION", __dir__)).strip
|
6
|
+
spec.authors = ["Brian Durand", "Winston Durand"]
|
7
|
+
spec.email = ["bbdurand@gmail.com", "me@winstondurand.com"]
|
10
8
|
|
11
|
-
spec.summary
|
12
|
-
spec.homepage
|
13
|
-
spec.license
|
9
|
+
spec.summary = "Protect from accidentally invoking Sidekiq jobs when there are open database transactions"
|
10
|
+
spec.homepage = "https://github.com/bdurand/sidekiq-transaction_guard"
|
11
|
+
spec.license = "MIT"
|
14
12
|
|
15
13
|
# Specify which files should be added to the gem when it is released.
|
16
14
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
17
|
-
ignore_files = %w
|
18
|
-
.
|
19
|
-
.travis.yml
|
15
|
+
ignore_files = %w[
|
16
|
+
.
|
20
17
|
Appraisals
|
21
18
|
Gemfile
|
22
19
|
Gemfile.lock
|
23
20
|
Rakefile
|
21
|
+
bin/
|
24
22
|
gemfiles/
|
25
23
|
spec/
|
26
|
-
|
27
|
-
spec.files
|
28
|
-
`git ls-files -z`.split("\x0").reject{ |f| ignore_files.any?{ |path| f.start_with?(path) } }
|
24
|
+
]
|
25
|
+
spec.files = Dir.chdir(__dir__) do
|
26
|
+
`git ls-files -z`.split("\x0").reject { |f| ignore_files.any? { |path| f.start_with?(path) } }
|
29
27
|
end
|
30
|
-
|
31
|
-
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
|
+
|
32
29
|
spec.require_paths = ["lib"]
|
33
30
|
|
34
|
-
spec.required_ruby_version =
|
31
|
+
spec.required_ruby_version = ">= 2.2.2"
|
35
32
|
|
36
33
|
spec.add_dependency "activerecord", ">= 4.0"
|
37
34
|
spec.add_dependency "sidekiq", ">= 3.0"
|
38
35
|
|
39
|
-
spec.add_development_dependency "bundler"
|
40
|
-
spec.add_development_dependency "rake"
|
41
|
-
spec.add_development_dependency "rspec", "~> 3.0"
|
42
|
-
spec.add_development_dependency "database_cleaner"
|
43
|
-
spec.add_development_dependency "sqlite3"
|
44
|
-
spec.add_development_dependency "appraisal"
|
36
|
+
spec.add_development_dependency "bundler"
|
45
37
|
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sidekiq-transaction_guard
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Durand
|
8
8
|
- Winston Durand
|
9
|
-
autorequire:
|
10
|
-
bindir:
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2023-12-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -41,76 +41,6 @@ dependencies:
|
|
41
41
|
version: '3.0'
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: bundler
|
44
|
-
requirement: !ruby/object:Gem::Requirement
|
45
|
-
requirements:
|
46
|
-
- - "~>"
|
47
|
-
- !ruby/object:Gem::Version
|
48
|
-
version: '1.10'
|
49
|
-
type: :development
|
50
|
-
prerelease: false
|
51
|
-
version_requirements: !ruby/object:Gem::Requirement
|
52
|
-
requirements:
|
53
|
-
- - "~>"
|
54
|
-
- !ruby/object:Gem::Version
|
55
|
-
version: '1.10'
|
56
|
-
- !ruby/object:Gem::Dependency
|
57
|
-
name: rake
|
58
|
-
requirement: !ruby/object:Gem::Requirement
|
59
|
-
requirements:
|
60
|
-
- - ">="
|
61
|
-
- !ruby/object:Gem::Version
|
62
|
-
version: '0'
|
63
|
-
type: :development
|
64
|
-
prerelease: false
|
65
|
-
version_requirements: !ruby/object:Gem::Requirement
|
66
|
-
requirements:
|
67
|
-
- - ">="
|
68
|
-
- !ruby/object:Gem::Version
|
69
|
-
version: '0'
|
70
|
-
- !ruby/object:Gem::Dependency
|
71
|
-
name: rspec
|
72
|
-
requirement: !ruby/object:Gem::Requirement
|
73
|
-
requirements:
|
74
|
-
- - "~>"
|
75
|
-
- !ruby/object:Gem::Version
|
76
|
-
version: '3.0'
|
77
|
-
type: :development
|
78
|
-
prerelease: false
|
79
|
-
version_requirements: !ruby/object:Gem::Requirement
|
80
|
-
requirements:
|
81
|
-
- - "~>"
|
82
|
-
- !ruby/object:Gem::Version
|
83
|
-
version: '3.0'
|
84
|
-
- !ruby/object:Gem::Dependency
|
85
|
-
name: database_cleaner
|
86
|
-
requirement: !ruby/object:Gem::Requirement
|
87
|
-
requirements:
|
88
|
-
- - ">="
|
89
|
-
- !ruby/object:Gem::Version
|
90
|
-
version: '0'
|
91
|
-
type: :development
|
92
|
-
prerelease: false
|
93
|
-
version_requirements: !ruby/object:Gem::Requirement
|
94
|
-
requirements:
|
95
|
-
- - ">="
|
96
|
-
- !ruby/object:Gem::Version
|
97
|
-
version: '0'
|
98
|
-
- !ruby/object:Gem::Dependency
|
99
|
-
name: sqlite3
|
100
|
-
requirement: !ruby/object:Gem::Requirement
|
101
|
-
requirements:
|
102
|
-
- - ">="
|
103
|
-
- !ruby/object:Gem::Version
|
104
|
-
version: '0'
|
105
|
-
type: :development
|
106
|
-
prerelease: false
|
107
|
-
version_requirements: !ruby/object:Gem::Requirement
|
108
|
-
requirements:
|
109
|
-
- - ">="
|
110
|
-
- !ruby/object:Gem::Version
|
111
|
-
version: '0'
|
112
|
-
- !ruby/object:Gem::Dependency
|
113
|
-
name: appraisal
|
114
44
|
requirement: !ruby/object:Gem::Requirement
|
115
45
|
requirements:
|
116
46
|
- - ">="
|
@@ -123,7 +53,7 @@ dependencies:
|
|
123
53
|
- - ">="
|
124
54
|
- !ruby/object:Gem::Version
|
125
55
|
version: '0'
|
126
|
-
description:
|
56
|
+
description:
|
127
57
|
email:
|
128
58
|
- bbdurand@gmail.com
|
129
59
|
- me@winstondurand.com
|
@@ -145,7 +75,7 @@ homepage: https://github.com/bdurand/sidekiq-transaction_guard
|
|
145
75
|
licenses:
|
146
76
|
- MIT
|
147
77
|
metadata: {}
|
148
|
-
post_install_message:
|
78
|
+
post_install_message:
|
149
79
|
rdoc_options: []
|
150
80
|
require_paths:
|
151
81
|
- lib
|
@@ -160,8 +90,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
160
90
|
- !ruby/object:Gem::Version
|
161
91
|
version: '0'
|
162
92
|
requirements: []
|
163
|
-
rubygems_version: 3.
|
164
|
-
signing_key:
|
93
|
+
rubygems_version: 3.4.20
|
94
|
+
signing_key:
|
165
95
|
specification_version: 4
|
166
96
|
summary: Protect from accidentally invoking Sidekiq jobs when there are open database
|
167
97
|
transactions
|