diff --git a/lib/distributed_cache.rb b/lib/distributed_cache.rb index 4a0a0348cae..54563704d30 100644 --- a/lib/distributed_cache.rb +++ b/lib/distributed_cache.rb @@ -10,6 +10,7 @@ require 'base64' class DistributedCache class Manager + CHANNEL_NAME ||= '/distributed_hash'.freeze def initialize(message_bus = nil) @subscribers = [] @@ -31,7 +32,7 @@ class DistributedCache begin current = @subscribers[i] - next if payload["origin"] == current.identity + next if payload["origin"] == current.identity && !Rails.env.test? next if current.key != payload["hash_key"] next if payload["discourse_version"] != Discourse.git_version @@ -51,15 +52,11 @@ class DistributedCache end end - def channel_name - "/distributed_hash".freeze - end - def ensure_subscribe! return if @subscribed @lock.synchronize do return if @subscribed - @message_bus.subscribe(channel_name) do |message| + @message_bus.subscribe(CHANNEL_NAME) do |message| @lock.synchronize do process_message(message) end @@ -72,7 +69,7 @@ class DistributedCache message[:origin] = hash.identity message[:hash_key] = hash.key message[:discourse_version] = Discourse.git_version - @message_bus.publish(channel_name, message, user_ids: [-1]) + @message_bus.publish(CHANNEL_NAME, message, user_ids: [-1]) end def set(hash, key, value) @@ -143,13 +140,12 @@ class DistributedCache end def hash(db = nil) - db ||= begin + db = if @namespace - RailsMultisite::ConnectionManagement.current_db + db || RailsMultisite::ConnectionManagement.current_db else RailsMultisite::ConnectionManagement::DEFAULT end - end @data[db] ||= ThreadSafe::Hash.new end diff --git a/spec/multisite/distributed_cache_spec.rb b/spec/multisite/distributed_cache_spec.rb new file mode 100644 index 00000000000..6267e181941 --- /dev/null +++ b/spec/multisite/distributed_cache_spec.rb @@ -0,0 +1,48 @@ +require 'rails_helper' + +RSpec.describe 'Multisite SiteSettings' do + let(:conn) { RailsMultisite::ConnectionManagement } + + before do + conn.config_filename = "spec/fixtures/multisite/two_dbs.yml" + conn.load_settings! + conn.remove_class_variable(:@@current_db) + end + + after do + conn.clear_settings! + + [:@@db_spec_cache, :@@host_spec_cache, :@@default_spec].each do |class_variable| + conn.remove_class_variable(class_variable) + end + + conn.set_current_db + end + + def cache(name, namespace: true) + DistributedCache.new(name, namespace: namespace) + end + + context 'without namespace' do + let(:cache1) { cache('test', namespace: false) } + + it 'does not leak state across multisite' do + cache1['default'] = true + + expect(cache1.hash).to eq('default' => true) + + conn.with_connection('second') do + message = MessageBus.track_publish(DistributedCache::Manager::CHANNEL_NAME) do + cache1['second'] = true + end.first + + expect(message.data[:hash_key]).to eq('test') + expect(message.data[:op]).to eq(:set) + expect(message.data[:key]).to eq('second') + expect(message.data[:value]).to eq(true) + end + + expect(cache1.hash).to eq('default' => true, 'second' => true) + end + end +end