diff options
Diffstat (limited to 'lib/gitlab/issuables_count_for_state.rb')
-rw-r--r-- | lib/gitlab/issuables_count_for_state.rb | 47 |
1 files changed, 44 insertions, 3 deletions
diff --git a/lib/gitlab/issuables_count_for_state.rb b/lib/gitlab/issuables_count_for_state.rb index 6b33b60e850..f11dd520d2d 100644 --- a/lib/gitlab/issuables_count_for_state.rb +++ b/lib/gitlab/issuables_count_for_state.rb @@ -5,11 +5,14 @@ module Gitlab class IssuablesCountForState # The name of the Gitlab::SafeRequestStore cache key. CACHE_KEY = :issuables_count_for_state + # The expiration time for the Rails cache. + CACHE_EXPIRES_IN = 1.hour + THRESHOLD = 1000 # The state values that can be safely casted to a Symbol. STATES = %w[opened closed merged all].freeze - attr_reader :project + attr_reader :project, :finder def self.declarative_policy_class 'IssuablePolicy' @@ -18,11 +21,12 @@ module Gitlab # finder - The finder class to use for retrieving the issuables. # fast_fail - restrict counting to a shorter period, degrading gracefully on # failure - def initialize(finder, project = nil, fast_fail: false) + def initialize(finder, project = nil, fast_fail: false, store_in_redis_cache: false) @finder = finder @project = project @fast_fail = fast_fail @cache = Gitlab::SafeRequestStore[CACHE_KEY] ||= initialize_cache + @store_in_redis_cache = store_in_redis_cache end def for_state_or_opened(state = nil) @@ -52,7 +56,16 @@ module Gitlab private def cache_for_finder - @cache[@finder] + cached_counts = Rails.cache.read(redis_cache_key, cache_options) if cache_issues_count? + + cached_counts ||= @cache[finder] + return cached_counts if cached_counts.empty? + + if cache_issues_count? && cached_counts.values.all? { |count| count >= THRESHOLD } + Rails.cache.write(redis_cache_key, cached_counts, cache_options) + end + + cached_counts end def cast_state_to_symbol?(state) @@ -108,5 +121,33 @@ module Gitlab "Count of failed calls to IssuableFinder#count_by_state with fast failure" ).increment end + + def cache_issues_count? + @store_in_redis_cache && + finder.instance_of?(IssuesFinder) && + parent_group.present? && + !params_include_filters? + end + + def parent_group + finder.params.group + end + + def redis_cache_key + ['group', parent_group&.id, 'issues'] + end + + def cache_options + { expires_in: CACHE_EXPIRES_IN } + end + + def params_include_filters? + non_filtering_params = %i[ + scope state sort group_id include_subgroups + attempt_group_search_optimizations non_archived issue_types + ] + + finder.params.except(*non_filtering_params).values.any? + end end end |