summaryrefslogtreecommitdiff
path: root/app/models/broadcast_message.rb
diff options
context:
space:
mode:
authorStan Hu <stanhu@gmail.com>2018-12-07 11:16:45 -0800
committerStan Hu <stanhu@gmail.com>2018-12-08 22:06:07 -0800
commitcde78f7f4eaec2740c6e91c7d225d701d0097ec0 (patch)
treee62f795f3a92d77c2ac2991e3b95f6c6ded8c6a9 /app/models/broadcast_message.rb
parent7cb0dd98590e8fdd7483b9f61643a0daa23c2b67 (diff)
downloadgitlab-ce-cde78f7f4eaec2740c6e91c7d225d701d0097ec0.tar.gz
Avoid caching BroadcastMessage as an ActiveRecord object
When a Rails 4 host serializes a BroadcastMessage, it will serialize `ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Integer`, which does not exist in Rails 5. This will cause Error 500s on a Rails 5 reading from this cache. To make Rails 4 and 5 play well together, store the data as JSON and construct the ActiveRecord objects from JSON. Closes https://gitlab.com/gitlab-org/gitlab-ce/issues/55034
Diffstat (limited to 'app/models/broadcast_message.rb')
-rw-r--r--app/models/broadcast_message.rb42
1 files changed, 39 insertions, 3 deletions
diff --git a/app/models/broadcast_message.rb b/app/models/broadcast_message.rb
index baf8adb318b..277f7c2717c 100644
--- a/app/models/broadcast_message.rb
+++ b/app/models/broadcast_message.rb
@@ -16,14 +16,20 @@ class BroadcastMessage < ActiveRecord::Base
default_value_for :color, '#E75E40'
default_value_for :font, '#FFFFFF'
- CACHE_KEY = 'broadcast_message_current'.freeze
+ CACHE_KEY = 'broadcast_message_current_json'.freeze
+ LEGACY_CACHE_KEY = 'broadcast_message_current'.freeze
after_commit :flush_redis_cache
def self.current
- messages = Rails.cache.fetch(CACHE_KEY, expires_in: cache_expires_in) { current_and_future_messages.to_a }
+ raw_messages = Rails.cache.fetch(CACHE_KEY, expires_in: cache_expires_in) do
+ remove_legacy_cache_key
+ current_and_future_messages.to_json
+ end
- return messages if messages.empty?
+ messages = decode_messages(raw_messages)
+
+ return [] unless messages&.present?
now_or_future = messages.select(&:now_or_future?)
@@ -34,6 +40,27 @@ class BroadcastMessage < ActiveRecord::Base
now_or_future.select(&:now?)
end
+ def self.decode_messages(raw_messages)
+ return unless raw_messages&.present?
+
+ message_list = ActiveSupport::JSON.decode(raw_messages)
+
+ return unless message_list.is_a?(Array)
+
+ valid_attr = BroadcastMessage.attribute_names
+
+ message_list.map do |raw|
+ BroadcastMessage.new(raw) if valid_cache_entry?(raw, valid_attr)
+ end.compact
+ rescue ActiveSupport::JSON.parse_error
+ end
+
+ def self.valid_cache_entry?(raw, valid_attr)
+ return false unless raw.is_a?(Hash)
+
+ (raw.keys - valid_attr).empty?
+ end
+
def self.current_and_future_messages
where('ends_at > :now', now: Time.zone.now).order_id_asc
end
@@ -42,6 +69,14 @@ class BroadcastMessage < ActiveRecord::Base
nil
end
+ # This can be removed in GitLab 12.0+
+ # The old cache key had an indefinite lifetime, and in an HA
+ # environment a one-shot migration would not work because the cache
+ # would be repopulated by a node that has not been upgraded.
+ def self.remove_legacy_cache_key
+ Rails.cache.delete(LEGACY_CACHE_KEY)
+ end
+
def active?
started? && !ended?
end
@@ -68,5 +103,6 @@ class BroadcastMessage < ActiveRecord::Base
def flush_redis_cache
Rails.cache.delete(CACHE_KEY)
+ self.class.remove_legacy_cache_key
end
end