Merge branch '58375-reactive-caching-changes' into 'master'
Allow reactive caching to be used in services See merge request gitlab-org/gitlab-ce!26839
This commit is contained in:
commit
465f82e32c
4 changed files with 92 additions and 3 deletions
|
@ -29,6 +29,40 @@
|
|||
# However, it will enqueue a background worker to call `#calculate_reactive_cache`
|
||||
# and set an initial cache lifetime of ten minutes.
|
||||
#
|
||||
# The background worker needs to find or generate the object on which
|
||||
# `with_reactive_cache` was called.
|
||||
# The default behaviour can be overridden by defining a custom
|
||||
# `reactive_cache_worker_finder`.
|
||||
# Otherwise the background worker will use the class name and primary key to get
|
||||
# the object using the ActiveRecord find_by method.
|
||||
#
|
||||
# class Bar
|
||||
# include ReactiveCaching
|
||||
#
|
||||
# self.reactive_cache_key = ->() { ["bar", "thing"] }
|
||||
# self.reactive_cache_worker_finder = ->(_id, *args) { from_cache(*args) }
|
||||
#
|
||||
# def self.from_cache(var1, var2)
|
||||
# # This method will be called by the background worker with "bar1" and
|
||||
# # "bar2" as arguments.
|
||||
# new(var1, var2)
|
||||
# end
|
||||
#
|
||||
# def initialize(var1, var2)
|
||||
# # ...
|
||||
# end
|
||||
#
|
||||
# def calculate_reactive_cache
|
||||
# # Expensive operation here. The return value of this method is cached
|
||||
# end
|
||||
#
|
||||
# def result
|
||||
# with_reactive_cache("bar1", "bar2") do |data|
|
||||
# # ...
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# Each time the background job completes, it stores the return value of
|
||||
# `#calculate_reactive_cache`. It is also re-enqueued to run again after
|
||||
# `reactive_cache_refresh_interval`, so keeping the stored value up to date.
|
||||
|
@ -52,6 +86,7 @@ module ReactiveCaching
|
|||
class_attribute :reactive_cache_key
|
||||
class_attribute :reactive_cache_lifetime
|
||||
class_attribute :reactive_cache_refresh_interval
|
||||
class_attribute :reactive_cache_worker_finder
|
||||
|
||||
# defaults
|
||||
self.reactive_cache_lease_timeout = 2.minutes
|
||||
|
@ -59,6 +94,10 @@ module ReactiveCaching
|
|||
self.reactive_cache_refresh_interval = 1.minute
|
||||
self.reactive_cache_lifetime = 10.minutes
|
||||
|
||||
self.reactive_cache_worker_finder = ->(id, *_args) do
|
||||
find_by(primary_key => id)
|
||||
end
|
||||
|
||||
def calculate_reactive_cache(*args)
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
class ReactiveCachingWorker
|
||||
include ApplicationWorker
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def perform(class_name, id, *args)
|
||||
klass = begin
|
||||
class_name.constantize
|
||||
|
@ -12,7 +11,9 @@ class ReactiveCachingWorker
|
|||
end
|
||||
return unless klass
|
||||
|
||||
klass.find_by(klass.primary_key => id).try(:exclusively_update_reactive_cache!, *args)
|
||||
klass
|
||||
.reactive_cache_worker_finder
|
||||
.call(id, *args)
|
||||
.try(:exclusively_update_reactive_cache!, *args)
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
end
|
||||
|
|
5
changelogs/unreleased/58375-reactive-caching-changes.yml
Normal file
5
changelogs/unreleased/58375-reactive-caching-changes.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Allow reactive caching to be used in services
|
||||
merge_request: 26839
|
||||
author:
|
||||
type: added
|
|
@ -16,6 +16,10 @@ describe ReactiveCaching, :use_clean_rails_memory_store_caching do
|
|||
|
||||
attr_reader :id
|
||||
|
||||
def self.primary_key
|
||||
:id
|
||||
end
|
||||
|
||||
def initialize(id, &blk)
|
||||
@id = id
|
||||
@calculator = blk
|
||||
|
@ -106,6 +110,46 @@ describe ReactiveCaching, :use_clean_rails_memory_store_caching do
|
|||
end
|
||||
end
|
||||
|
||||
describe '.reactive_cache_worker_finder' do
|
||||
context 'with default reactive_cache_worker_finder' do
|
||||
let(:args) { %w(other args) }
|
||||
|
||||
before do
|
||||
allow(instance.class).to receive(:find_by).with(id: instance.id)
|
||||
.and_return(instance)
|
||||
end
|
||||
|
||||
it 'calls the activerecord find_by method' do
|
||||
result = instance.class.reactive_cache_worker_finder.call(instance.id, *args)
|
||||
|
||||
expect(result).to eq(instance)
|
||||
expect(instance.class).to have_received(:find_by).with(id: instance.id)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with custom reactive_cache_worker_finder' do
|
||||
let(:args) { %w(arg1 arg2) }
|
||||
let(:instance) { CustomFinderCacheTest.new(666, &calculation) }
|
||||
|
||||
class CustomFinderCacheTest < CacheTest
|
||||
self.reactive_cache_worker_finder = ->(_id, *args) { from_cache(*args) }
|
||||
|
||||
def self.from_cache(*args); end
|
||||
end
|
||||
|
||||
before do
|
||||
allow(instance.class).to receive(:from_cache).with(*args).and_return(instance)
|
||||
end
|
||||
|
||||
it 'overrides the default reactive_cache_worker_finder' do
|
||||
result = instance.class.reactive_cache_worker_finder.call(instance.id, *args)
|
||||
|
||||
expect(result).to eq(instance)
|
||||
expect(instance.class).to have_received(:from_cache).with(*args)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#clear_reactive_cache!' do
|
||||
before do
|
||||
stub_reactive_cache(instance, 4)
|
||||
|
|
Loading…
Reference in a new issue