Commit aeb2869f authored by Nick Thomas's avatar Nick Thomas

Prevent bad data being added to application settings when Redis is unavailable

parent cd735170
...@@ -184,6 +184,9 @@ class ApplicationSetting < ActiveRecord::Base ...@@ -184,6 +184,9 @@ class ApplicationSetting < ActiveRecord::Base
Rails.cache.fetch(CACHE_KEY) do Rails.cache.fetch(CACHE_KEY) do
ApplicationSetting.last ApplicationSetting.last
end end
rescue
# Fall back to an uncached value if there are any problems (e.g. redis down)
ApplicationSetting.last
end end
def self.expire def self.expire
......
---
title: Prevent bad data being added to application settings when Redis is unavailable
merge_request: 12750
author:
...@@ -33,12 +33,7 @@ module Gitlab ...@@ -33,12 +33,7 @@ module Gitlab
def uncached_application_settings def uncached_application_settings
return fake_application_settings unless connect_to_db? return fake_application_settings unless connect_to_db?
# This loads from the database into the cache, so handle Redis errors
begin
db_settings = ::ApplicationSetting.current db_settings = ::ApplicationSetting.current
rescue ::Redis::BaseError, ::Errno::ENOENT
# In case Redis isn't running or the Redis UNIX socket file is not available
end
# If there are pending migrations, it's possible there are columns that # If there are pending migrations, it's possible there are columns that
# need to be added to the application settings. To prevent Rake tasks # need to be added to the application settings. To prevent Rake tasks
......
...@@ -27,10 +27,23 @@ describe Gitlab::CurrentSettings do ...@@ -27,10 +27,23 @@ describe Gitlab::CurrentSettings do
end end
it 'falls back to DB if Redis fails' do it 'falls back to DB if Redis fails' do
db_settings = ApplicationSetting.create!(ApplicationSetting.defaults)
expect(ApplicationSetting).to receive(:cached).and_raise(::Redis::BaseError) expect(ApplicationSetting).to receive(:cached).and_raise(::Redis::BaseError)
expect(ApplicationSetting).to receive(:last).and_call_original expect(Rails.cache).to receive(:fetch).with(ApplicationSetting::CACHE_KEY).and_raise(Redis::BaseError)
expect(current_application_settings).to be_a(ApplicationSetting) expect(current_application_settings).to eq(db_settings)
end
it 'creates default ApplicationSettings if none are present' do
expect(ApplicationSetting).to receive(:cached).and_raise(::Redis::BaseError)
expect(Rails.cache).to receive(:fetch).with(ApplicationSetting::CACHE_KEY).and_raise(Redis::BaseError)
settings = current_application_settings
expect(settings).to be_a(ApplicationSetting)
expect(settings).to be_persisted
expect(settings).to have_attributes(ApplicationSetting.defaults)
end end
context 'with migrations pending' do context 'with migrations pending' do
......
...@@ -155,6 +155,18 @@ describe ApplicationSetting, models: true do ...@@ -155,6 +155,18 @@ describe ApplicationSetting, models: true do
end end
end end
describe '.current' do
context 'redis unavailable' do
it 'returns an ApplicationSetting' do
allow(Rails.cache).to receive(:fetch).and_call_original
allow(ApplicationSetting).to receive(:last).and_return(:last)
expect(Rails.cache).to receive(:fetch).with(ApplicationSetting::CACHE_KEY).and_raise(ArgumentError)
expect(ApplicationSetting.current).to eq(:last)
end
end
end
context 'restricted signup domains' do context 'restricted signup domains' do
it 'sets single domain' do it 'sets single domain' do
setting.domain_whitelist_raw = 'example.com' setting.domain_whitelist_raw = 'example.com'
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment