Commit 585f88b4 authored by Igor Drozdov's avatar Igor Drozdov

Merge branch 'sh-cache-license-data' into 'master'

Cache license data in a process-memory cache

See merge request gitlab-org/gitlab!50318
parents 828b9ed3 3a577f32
---
title: Cache license data in a process-memory cache
merge_request: 50318
author:
type: performance
...@@ -243,6 +243,8 @@ class License < ApplicationRecord ...@@ -243,6 +243,8 @@ class License < ApplicationRecord
scope :recent, -> { reorder(id: :desc) } scope :recent, -> { reorder(id: :desc) }
scope :last_hundred, -> { recent.limit(100) } scope :last_hundred, -> { recent.limit(100) }
CACHE_KEY = :current_license
class << self class << self
def features_for_plan(plan) def features_for_plan(plan)
FEATURES_BY_PLAN.fetch(plan, []) FEATURES_BY_PLAN.fetch(plan, [])
...@@ -261,11 +263,12 @@ class License < ApplicationRecord ...@@ -261,11 +263,12 @@ class License < ApplicationRecord
end end
def current def current
if RequestStore.active? cache.fetch(CACHE_KEY, as: License, expires_in: 1.minute) { load_license }
RequestStore.fetch(:current_license) { load_license } end
else
load_license def cache
end Gitlab::SafeRequestStore[:license_cache] ||=
Gitlab::JsonCache.new(namespace: :ee, backend: ::Gitlab::ProcessMemoryCache.cache_backend)
end end
def all_plans def all_plans
...@@ -275,7 +278,7 @@ class License < ApplicationRecord ...@@ -275,7 +278,7 @@ class License < ApplicationRecord
delegate :block_changes?, :feature_available?, to: :current, allow_nil: true delegate :block_changes?, :feature_available?, to: :current, allow_nil: true
def reset_current def reset_current
RequestStore.delete(:current_license) cache.expire(CACHE_KEY)
end end
def load_license def load_license
......
...@@ -415,7 +415,7 @@ RSpec.describe License do ...@@ -415,7 +415,7 @@ RSpec.describe License do
end end
end end
describe '.current' do describe '.current', :request_store, :use_clean_rails_memory_store_caching do
context 'when licenses table does not exist' do context 'when licenses table does not exist' do
it 'returns nil' do it 'returns nil' do
allow(described_class).to receive(:table_exists?).and_return(false) allow(described_class).to receive(:table_exists?).and_return(false)
...@@ -442,12 +442,28 @@ RSpec.describe License do ...@@ -442,12 +442,28 @@ RSpec.describe License do
end end
context 'when the license is valid' do context 'when the license is valid' do
let!(:current_license) { create_list(:license, 2).last }
it 'returns the license' do it 'returns the license' do
current_license = create_list(:license, 2).last
create(:license, data: create(:gitlab_license, starts_at: Date.current + 1.month).export) create(:license, data: create(:gitlab_license, starts_at: Date.current + 1.month).export)
expect(described_class.current).to eq(current_license) expect(described_class.current).to eq(current_license)
end end
it 'caches the license' do
described_class.reset_current
expect(described_class).to receive(:load_license).once.and_call_original
2.times do
expect(described_class.current).to eq(current_license)
end
travel_to(61.seconds.from_now) do
expect(described_class).to receive(:load_license).once.and_call_original
expect(described_class.current).to eq(current_license)
end
end
end end
end end
......
...@@ -69,6 +69,8 @@ RSpec.describe 'Project.cluster_agents' do ...@@ -69,6 +69,8 @@ RSpec.describe 'Project.cluster_agents' do
end end
it 'does not suffer from N+1 performance issues' do it 'does not suffer from N+1 performance issues' do
post_graphql(query, current_user: current_user)
expect do expect do
post_graphql(query, current_user: current_user) post_graphql(query, current_user: current_user)
end.to issue_same_number_of_queries_as { post_graphql(query, current_user: current_user, variables: [first.with(1)]) } end.to issue_same_number_of_queries_as { post_graphql(query, current_user: current_user, variables: [first.with(1)]) }
......
...@@ -850,12 +850,13 @@ RSpec.describe ApplicationSetting do ...@@ -850,12 +850,13 @@ RSpec.describe ApplicationSetting do
end end
end end
describe '#instance_review_permitted?', :request_store do describe '#instance_review_permitted?', :request_store, :use_clean_rails_memory_store_caching do
subject { setting.instance_review_permitted? } subject { setting.instance_review_permitted? }
before do before do
RequestStore.store[:current_license] = nil allow(License).to receive(:current).and_return(nil) if Gitlab.ee?
expect(Rails.cache).to receive(:fetch).and_return( allow(Rails.cache).to receive(:fetch).and_call_original
expect(Rails.cache).to receive(:fetch).with('limited_users_count', anything).and_return(
::ApplicationSetting::INSTANCE_REVIEW_MIN_USERS + users_over_minimum ::ApplicationSetting::INSTANCE_REVIEW_MIN_USERS + users_over_minimum
) )
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