sidekiq-transaction_guard 1.1.2 → 1.1.3

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
  SHA256:
3
- metadata.gz: 4e78c153bc733cc296bd92ee4ef71be1999660724aed0a4421c68a86bea98233
4
- data.tar.gz: '095f61285d5cb8d7aade4f5c343ea7a6d7e3b548a3ec8e6a128dae5e0d64e740'
3
+ metadata.gz: 5c0d2035a276a481304f3b833e10119704d05583e63eda918a34da4a83823ab1
4
+ data.tar.gz: beb93e6793e86312f448d536eb4ba51b4b0b5290c5b45ebfe2a5916e37a00b5e
5
5
  SHA512:
6
- metadata.gz: 386abe0d3a8b40f22358dd7e30bd808a6e9837e5dc0d34731b5693ee8a02375edee77a425c56e97efc3deec356207aaa7b247618ceda42d25d9da9756d653e7f
7
- data.tar.gz: c4c88c36fc2b38e6ddbbec3933873f8983ba9a389d9d1554c4913e1ccbf160ba5ab1768a73e3120cb9fca40a92e5dac159518b627452c3ca5eae8fe517ae1453
6
+ metadata.gz: 1de9763227c618c2ecd3e4c7af601f20db01b388eac1632678ac3521f4b1d7baa93669de29e00d8cfe718a4ef9502967c593e17e4b8fec47f46804b2b9453de2
7
+ data.tar.gz: 97732ce309894eafc91fa5e4e2f1ff89cee2d1aeb8ed33da0e6e9496e3c635fe724b28c449c7dff54e3d3d16c1568d8b8c64f961466782b5d2643139a98d8594
data/CHANGELOG.md CHANGED
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## 1.1.3
8
+
9
+ ### Fixed
10
+
11
+ - Transactions opened by the connection pool pinning machinery used by transactional tests in Rails 7.2+ are no longer counted as application transactions. Rails 7.2 pins a single connection wrapped in a non-joinable transaction and shares it with every thread, but the transaction level baseline captured by the test integrations is stored per thread. Threads other than the test runner thread (e.g. Capybara server threads, ActionCable workers, or inline Sidekiq jobs in system tests) had no baseline, so every job they enqueued was falsely flagged as inside a transaction. The allowed transaction level is now derived from the pool's pinned connection state as well, which is visible from all threads. Transactions opened by application code, including non-joinable ones, are still counted. The pinned connection state is only consulted once a test integration has started a testing context, so pinning a connection outside of tests does not bypass the guard.
12
+
7
13
  ## 1.1.2
8
14
 
9
15
  ### Fixed
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.1.2
1
+ 1.1.3
@@ -15,6 +15,7 @@ module Sidekiq
15
15
  @connection_classes = Set.new
16
16
  @notify = nil
17
17
  @mode = :warn
18
+ @testing_context = false
18
19
 
19
20
  class << self
20
21
  VALID_MODES = [:warn, :stderr, :error, :disabled].freeze
@@ -134,11 +135,10 @@ module Sidekiq
134
135
  def in_transaction?
135
136
  connection_classes.any? do |connection_class|
136
137
  connection = active_connection(connection_class)
137
- if connection
138
- connection.open_transactions > allowed_transaction_level(connection_class)
139
- else
140
- false
141
- end
138
+ next false unless connection
139
+
140
+ connection.open_transactions > allowed_transaction_level(connection_class) &&
141
+ application_transaction_open?(connection)
142
142
  end
143
143
  end
144
144
 
@@ -194,6 +194,7 @@ module Sidekiq
194
194
  var = :sidekiq_rails_transaction_guard
195
195
  saved_state = Thread.current[var]
196
196
  Thread.current[var] = (saved_state ? saved_state.dup : {})
197
+ @testing_context = true
197
198
  saved_state
198
199
  end
199
200
 
@@ -242,6 +243,42 @@ module Sidekiq
242
243
  (connection_counts && connection_counts[connection_class.name]) || 0
243
244
  end
244
245
 
246
+ # Return true if the connection has any open transaction that was not opened by
247
+ # the connection pool pinning machinery (Rails 7.2+). Transactional tests pin a
248
+ # connection and wrap it in a non-joinable transaction that the pool then shares
249
+ # with every thread. Those wrapper transactions are test scaffolding, not
250
+ # application transactions, so they never count against the guard. The pin state
251
+ # is read from the pool rather than from a thread local so that threads without a
252
+ # baseline (e.g. web server threads in system tests) get the correct level.
253
+ def application_transaction_open?(connection)
254
+ return true unless @testing_context
255
+ return true unless connection.respond_to?(:pinned)
256
+
257
+ # The pool changes the pin state under the connection lock. Hold it so the
258
+ # transaction count and the pin state cannot be read from different states.
259
+ connection.lock.synchronize do
260
+ next true unless connection.pinned
261
+
262
+ open_transactions = connection.open_transactions
263
+ open_transactions > pinned_transaction_count(connection, open_transactions)
264
+ end
265
+ end
266
+
267
+ # Return the number of open transactions on a pinned connection that belong to
268
+ # the pinning machinery. The pool counts pins rather than transactions, so the
269
+ # count is only trusted as far as the connection state supports it: it can never
270
+ # exceed the open transactions, and if it accounts for all of them then the
271
+ # innermost one must be non-joinable, since the wrappers always are. Anything
272
+ # else means the wrappers were closed outside of the pinning machinery and
273
+ # nothing should be discounted.
274
+ def pinned_transaction_count(connection, open_transactions)
275
+ depth = connection.pool.instance_variable_get(:@pinned_connections_depth).to_i
276
+ depth = open_transactions if depth > open_transactions
277
+ return 0 if depth == open_transactions && connection.current_transaction.joinable?
278
+
279
+ depth
280
+ end
281
+
245
282
  def add_client_middleware(config)
246
283
  config.client_middleware do |chain|
247
284
  unless chain.exists?(Sidekiq::TransactionGuard::Middleware)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq-transaction_guard
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2
4
+ version: 1.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Durand