Skip to content

Commit 074b19b

Browse files
authored
Add a disable_query_cache option to with_advisory_lock (#70)
1 parent 8f0a036 commit 074b19b

File tree

3 files changed

+35
-2
lines changed

3 files changed

+35
-2
lines changed

Diff for: README.md

+8
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,14 @@ If you want to see if the current Thread is holding a lock, you can call
9494
`Tag.current_advisory_lock` which will return the name of the current lock. If
9595
no lock is currently held, `.current_advisory_lock` returns `nil`.
9696

97+
### ActiveRecord Query Cache
98+
99+
You can optionally pass `disable_query_cache: true` to the options hash of
100+
`with_advisory_lock` in order to disable ActiveRecord's query cache. This can
101+
prevent problems when you query the database from within the lock and it returns
102+
stale results. More info on why this can be a problem can be
103+
[found here](https://github.com/ClosureTree/with_advisory_lock/issues/52)
104+
97105
## Installation
98106

99107
Add this line to your application's Gemfile:

Diff for: lib/with_advisory_lock/base.rb

+13-2
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,18 @@ def lock_was_acquired?
2121
LockStackItem = Struct.new(:name, :shared)
2222

2323
class Base
24-
attr_reader :connection, :lock_name, :timeout_seconds, :shared, :transaction
24+
attr_reader :connection, :lock_name, :timeout_seconds, :shared, :transaction, :disable_query_cache
2525

2626
def initialize(connection, lock_name, options)
2727
options = { timeout_seconds: options } unless options.respond_to?(:fetch)
28-
options.assert_valid_keys :timeout_seconds, :shared, :transaction
28+
options.assert_valid_keys :timeout_seconds, :shared, :transaction, :disable_query_cache
2929

3030
@connection = connection
3131
@lock_name = lock_name
3232
@timeout_seconds = options.fetch(:timeout_seconds, nil)
3333
@shared = options.fetch(:shared, false)
3434
@transaction = options.fetch(:transaction, false)
35+
@disable_query_cache = options.fetch(:disable_query_cache, false)
3536
end
3637

3738
def lock_str
@@ -53,6 +54,16 @@ def already_locked?
5354
end
5455

5556
def with_advisory_lock_if_needed(&block)
57+
if disable_query_cache
58+
return lock_and_yield do
59+
ActiveRecord::Base.uncached(&block)
60+
end
61+
end
62+
63+
lock_and_yield(&block)
64+
end
65+
66+
def lock_and_yield(&block)
5667
if already_locked?
5768
Result.new(true, yield)
5869
elsif timeout_seconds == 0

Diff for: test/concern_test.rb

+14
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,17 @@
1919
assert_respond_to(Label.new, :advisory_lock_exists?)
2020
end
2121
end
22+
23+
describe 'ActiveRecord query cache' do
24+
it 'does not disable quary cache by default' do
25+
ActiveRecord::Base.expects(:uncached).never
26+
27+
Tag.with_advisory_lock('lock') { Tag.first }
28+
end
29+
30+
it 'can disable ActiveRecord query cache' do
31+
ActiveRecord::Base.expects(:uncached).once
32+
33+
Tag.with_advisory_lock('a-lock', disable_query_cache: true) { Tag.first }
34+
end
35+
end

0 commit comments

Comments
 (0)