Skip to content

Commit

Permalink
Add a disable_query_cache option to with_advisory_lock (#70)
Browse files Browse the repository at this point in the history
  • Loading branch information
muxcmux authored Feb 11, 2023
1 parent 8f0a036 commit 074b19b
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 2 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ If you want to see if the current Thread is holding a lock, you can call
`Tag.current_advisory_lock` which will return the name of the current lock. If
no lock is currently held, `.current_advisory_lock` returns `nil`.

### ActiveRecord Query Cache

You can optionally pass `disable_query_cache: true` to the options hash of
`with_advisory_lock` in order to disable ActiveRecord's query cache. This can
prevent problems when you query the database from within the lock and it returns
stale results. More info on why this can be a problem can be
[found here](https://github.com/ClosureTree/with_advisory_lock/issues/52)

## Installation

Add this line to your application's Gemfile:
Expand Down
15 changes: 13 additions & 2 deletions lib/with_advisory_lock/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,18 @@ def lock_was_acquired?
LockStackItem = Struct.new(:name, :shared)

class Base
attr_reader :connection, :lock_name, :timeout_seconds, :shared, :transaction
attr_reader :connection, :lock_name, :timeout_seconds, :shared, :transaction, :disable_query_cache

def initialize(connection, lock_name, options)
options = { timeout_seconds: options } unless options.respond_to?(:fetch)
options.assert_valid_keys :timeout_seconds, :shared, :transaction
options.assert_valid_keys :timeout_seconds, :shared, :transaction, :disable_query_cache

@connection = connection
@lock_name = lock_name
@timeout_seconds = options.fetch(:timeout_seconds, nil)
@shared = options.fetch(:shared, false)
@transaction = options.fetch(:transaction, false)
@disable_query_cache = options.fetch(:disable_query_cache, false)
end

def lock_str
Expand All @@ -53,6 +54,16 @@ def already_locked?
end

def with_advisory_lock_if_needed(&block)
if disable_query_cache
return lock_and_yield do
ActiveRecord::Base.uncached(&block)
end
end

lock_and_yield(&block)
end

def lock_and_yield(&block)
if already_locked?
Result.new(true, yield)
elsif timeout_seconds == 0
Expand Down
14 changes: 14 additions & 0 deletions test/concern_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,17 @@
assert_respond_to(Label.new, :advisory_lock_exists?)
end
end

describe 'ActiveRecord query cache' do
it 'does not disable quary cache by default' do
ActiveRecord::Base.expects(:uncached).never

Tag.with_advisory_lock('lock') { Tag.first }
end

it 'can disable ActiveRecord query cache' do
ActiveRecord::Base.expects(:uncached).once

Tag.with_advisory_lock('a-lock', disable_query_cache: true) { Tag.first }
end
end

0 comments on commit 074b19b

Please sign in to comment.