Commit 5bc8987a authored by Sean McGivern's avatar Sean McGivern

Always use rate limiting Redis

We have deployed this change to GitLab.com and so we no longer need to
switch based on a feature flag or environment variable.
Gitlab::Redis::RateLimiting falls back to Gitlab::Redis::Cache when not
configured, which means that existing self-managed instances will
continue to work correctly.

Changelog: other
parent 21133fee
---
name: use_rate_limiting_store_for_application_rate_limiter
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/71196
rollout_issue_url: https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1249
milestone: '14.4'
type: development
group: group::scalability
default_enabled: false
......@@ -73,7 +73,7 @@ module Gitlab
value = 0
interval_value = interval || interval(key)
cache_store.with do |redis|
::Gitlab::Redis::RateLimiting.with do |redis|
cache_key = action_key(key, scope)
value = redis.incr(cache_key)
redis.expire(cache_key, interval_value) if value == 1
......@@ -109,14 +109,6 @@ module Gitlab
private
def cache_store
if ::Feature.enabled?(:use_rate_limiting_store_for_application_rate_limiter, default_enabled: :yaml)
::Gitlab::Redis::RateLimiting
else
::Gitlab::Redis::Cache
end
end
def threshold(key)
value = rate_limit_value_by_key(key, :threshold)
......
......@@ -15,18 +15,7 @@ module Gitlab
delegate :silence!, :mute, to: :@upstream_store
# Clean up in https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1249
def self.store
if ENV['USE_RATE_LIMITING_STORE_FOR_RACK_ATTACK'] == '1'
Gitlab::AuthLogger.info(message: 'Rack::Attack using rate limiting store')
::Gitlab::Redis::RateLimiting.cache_store
else
Gitlab::AuthLogger.info(message: 'Rack::Attack using cache store')
::Rails.cache
end
end
def initialize(upstream_store: self.class.store, notifier: ActiveSupport::Notifications)
def initialize(upstream_store: ::Gitlab::Redis::RateLimiting.cache_store, notifier: ActiveSupport::Notifications)
@upstream_store = upstream_store
@notifier = notifier
end
......
......@@ -20,6 +20,7 @@ RSpec.describe Gitlab::ApplicationRateLimiter do
subject { described_class }
before do
allow(Gitlab::Redis::RateLimiting).to receive(:with).and_yield(redis)
allow(described_class).to receive(:rate_limits).and_return(rate_limits)
end
......@@ -48,94 +49,73 @@ RSpec.describe Gitlab::ApplicationRateLimiter do
end
end
# Clean up in https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1249
shared_examples 'rate limiting' do
context 'when the key is an array of only ActiveRecord models' do
let(:scope) { [user, project] }
context 'when the key is an array of only ActiveRecord models' do
let(:scope) { [user, project] }
let(:cache_key) do
"application_rate_limiter:test_action:user:#{user.id}:project:#{project.id}"
end
it_behaves_like 'action rate limiter'
let(:cache_key) do
"application_rate_limiter:test_action:user:#{user.id}:project:#{project.id}"
end
context 'when they key a combination of ActiveRecord models and strings' do
let(:project) { create(:project, :public, :repository) }
let(:commit) { project.repository.commit }
let(:path) { 'app/controllers/groups_controller.rb' }
let(:scope) { [project, commit, path] }
it_behaves_like 'action rate limiter'
end
let(:cache_key) do
"application_rate_limiter:test_action:project:#{project.id}:commit:#{commit.sha}:#{path}"
end
context 'when they key a combination of ActiveRecord models and strings' do
let(:project) { create(:project, :public, :repository) }
let(:commit) { project.repository.commit }
let(:path) { 'app/controllers/groups_controller.rb' }
let(:scope) { [project, commit, path] }
it_behaves_like 'action rate limiter'
let(:cache_key) do
"application_rate_limiter:test_action:project:#{project.id}:commit:#{commit.sha}:#{path}"
end
describe '#log_request' do
let(:file_path) { 'master/README.md' }
let(:type) { :raw_blob_request_limit }
let(:fullpath) { "/#{project.full_path}/raw/#{file_path}" }
let(:request) do
double('request', ip: '127.0.0.1', request_method: 'GET', fullpath: fullpath)
end
let(:base_attributes) do
{
message: 'Application_Rate_Limiter_Request',
env: type,
remote_ip: '127.0.0.1',
request_method: 'GET',
path: fullpath
}
end
context 'without a current user' do
let(:current_user) { nil }
it_behaves_like 'action rate limiter'
end
it 'logs information to auth.log' do
expect(Gitlab::AuthLogger).to receive(:error).with(base_attributes).once
describe '#log_request' do
let(:file_path) { 'master/README.md' }
let(:type) { :raw_blob_request_limit }
let(:fullpath) { "/#{project.full_path}/raw/#{file_path}" }
subject.log_request(request, type, current_user)
end
end
let(:request) do
double('request', ip: '127.0.0.1', request_method: 'GET', fullpath: fullpath)
end
context 'with a current_user' do
let(:current_user) { create(:user) }
let(:base_attributes) do
{
message: 'Application_Rate_Limiter_Request',
env: type,
remote_ip: '127.0.0.1',
request_method: 'GET',
path: fullpath
}
end
let(:attributes) do
base_attributes.merge({
user_id: current_user.id,
username: current_user.username
})
end
context 'without a current user' do
let(:current_user) { nil }
it 'logs information to auth.log' do
expect(Gitlab::AuthLogger).to receive(:error).with(attributes).once
it 'logs information to auth.log' do
expect(Gitlab::AuthLogger).to receive(:error).with(base_attributes).once
subject.log_request(request, type, current_user)
end
subject.log_request(request, type, current_user)
end
end
end
context 'when use_rate_limiting_store_for_application_rate_limiter is enabled' do
before do
stub_feature_flags(use_rate_limiting_store_for_application_rate_limiter: true)
allow(Gitlab::Redis::RateLimiting).to receive(:with).and_yield(redis)
end
context 'with a current_user' do
let(:current_user) { create(:user) }
it_behaves_like 'rate limiting'
end
let(:attributes) do
base_attributes.merge({
user_id: current_user.id,
username: current_user.username
})
end
context 'when use_rate_limiting_store_for_application_rate_limiter is disabled' do
before do
stub_feature_flags(use_rate_limiting_store_for_application_rate_limiter: false)
allow(Gitlab::Redis::Cache).to receive(:with).and_yield(redis)
end
it 'logs information to auth.log' do
expect(Gitlab::AuthLogger).to receive(:error).with(attributes).once
it_behaves_like 'rate limiting'
subject.log_request(request, type, current_user)
end
end
end
end
......@@ -86,17 +86,4 @@ RSpec.describe Gitlab::RackAttack::InstrumentedCacheStore do
test_proc.call(subject)
end
end
# Remove in https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1249
describe '.store' do
it 'uses the rate limiting store when USE_RATE_LIMITING_STORE_FOR_RACK_ATTACK is set' do
stub_env('USE_RATE_LIMITING_STORE_FOR_RACK_ATTACK', '1')
expect(described_class.store).to eq(Gitlab::Redis::RateLimiting.cache_store)
end
it 'uses the cache store' do
expect(described_class.store).to eq(Rails.cache)
end
end
end
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