Class: Gitlab::Issues::Rebalancing::State
- Inherits:
-
Object
- Object
- Gitlab::Issues::Rebalancing::State
- Defined in:
- lib/gitlab/issues/rebalancing/state.rb
Constant Summary collapse
- REDIS_KEY_PREFIX =
"gitlab:issues-position-rebalances"
- CONCURRENT_RUNNING_REBALANCES_KEY =
"#{REDIS_KEY_PREFIX}:running_rebalances"
- RECENTLY_FINISHED_REBALANCE_PREFIX =
"#{REDIS_KEY_PREFIX}:recently_finished"
- REDIS_EXPIRY_TIME =
10.days
- MAX_NUMBER_OF_CONCURRENT_REBALANCES =
5
- NAMESPACE =
1
- PROJECT =
2
Class Method Summary collapse
- .fetch_rebalancing_groups_and_projects ⇒ Object
- .rebalance_recently_finished?(project_id, namespace_id) ⇒ Boolean
Instance Method Summary collapse
- #cache_current_index(index) ⇒ Object
- #cache_current_project_id(project_id) ⇒ Object
- #cache_issue_ids(issue_ids) ⇒ Object
- #can_start_rebalance? ⇒ Boolean
- #cleanup_cache ⇒ Object
- #concurrent_running_rebalances_count ⇒ Object
- #get_cached_issue_ids(index, limit) ⇒ Object
- #get_current_index ⇒ Object
- #get_current_project_id ⇒ Object
-
#initialize(root_namespace, projects) ⇒ State
constructor
A new instance of State.
- #issue_count ⇒ Object
- #rebalance_in_progress? ⇒ Boolean
- #refresh_keys_expiration ⇒ Object
- #remove_current_project_id_cache ⇒ Object
- #track_new_running_rebalance ⇒ Object
Constructor Details
#initialize(root_namespace, projects) ⇒ State
Returns a new instance of State.
16 17 18 19 20 21 |
# File 'lib/gitlab/issues/rebalancing/state.rb', line 16 def initialize(root_namespace, projects) @root_namespace = root_namespace @projects = projects @rebalanced_container_type = @root_namespace.is_a?(Group) ? NAMESPACE : PROJECT @rebalanced_container_id = @rebalanced_container_type == NAMESPACE ? @root_namespace.id : projects.take.id # rubocop:disable CodeReuse/ActiveRecord end |
Class Method Details
.fetch_rebalancing_groups_and_projects ⇒ Object
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/gitlab/issues/rebalancing/state.rb', line 140 def self.fetch_rebalancing_groups_and_projects namespace_ids = [] project_ids = [] current_rebalancing_containers.each do |string| container_type, container_id = string.split('/', 2).map(&:to_i) case container_type when NAMESPACE namespace_ids << container_id when PROJECT project_ids << container_id end end [namespace_ids, project_ids] end |
.rebalance_recently_finished?(project_id, namespace_id) ⇒ Boolean
133 134 135 136 137 138 |
# File 'lib/gitlab/issues/rebalancing/state.rb', line 133 def self.rebalance_recently_finished?(project_id, namespace_id) container_id = project_id || namespace_id container_type = project_id.present? ? PROJECT : NAMESPACE Gitlab::Redis::SharedState.with { |redis| redis.get(recently_finished_key(container_type, container_id)) } end |
Instance Method Details
#cache_current_index(index) ⇒ Object
76 77 78 |
# File 'lib/gitlab/issues/rebalancing/state.rb', line 76 def cache_current_index(index) with_redis { |redis| redis.set(current_index_key, index, ex: REDIS_EXPIRY_TIME) } end |
#cache_current_project_id(project_id) ⇒ Object
84 85 86 |
# File 'lib/gitlab/issues/rebalancing/state.rb', line 84 def cache_current_project_id(project_id) with_redis { |redis| redis.set(current_project_key, project_id, ex: REDIS_EXPIRY_TIME) } end |
#cache_issue_ids(issue_ids) ⇒ Object
59 60 61 62 63 64 65 66 67 68 |
# File 'lib/gitlab/issues/rebalancing/state.rb', line 59 def cache_issue_ids(issue_ids) with_redis do |redis| values = issue_ids.map { |issue| [issue.relative_position, issue.id] } redis.multi do |multi| multi.zadd(issue_ids_key, values) unless values.blank? multi.expire(issue_ids_key, REDIS_EXPIRY_TIME) end end end |
#can_start_rebalance? ⇒ Boolean
55 56 57 |
# File 'lib/gitlab/issues/rebalancing/state.rb', line 55 def can_start_rebalance? rebalance_in_progress? || concurrent_rebalance_within_limit? end |
#cleanup_cache ⇒ Object
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/gitlab/issues/rebalancing/state.rb', line 113 def cleanup_cache value = "#{rebalanced_container_type}/#{rebalanced_container_id}" # The clean up is done sequentially to be compatible with Redis Cluster # Do not use a pipeline as it fans-out in a Redis-Cluster setting and forego ordering guarantees with_redis do |redis| # srem followed by .del(issue_ids_key) to ensure that any subsequent redis errors would # result in a no-op job retry since current_index_key still exists redis.srem?(CONCURRENT_RUNNING_REBALANCES_KEY, value) redis.del(issue_ids_key) # delete current_index_key to ensure that subsequent redis errors would # result in a fresh job retry redis.del(current_index_key) # setting recently_finished_key last after job details is cleaned up redis.set(self.class.recently_finished_key(rebalanced_container_type, rebalanced_container_id), true, ex: 1.hour) end end |
#concurrent_running_rebalances_count ⇒ Object
34 35 36 |
# File 'lib/gitlab/issues/rebalancing/state.rb', line 34 def concurrent_running_rebalances_count with_redis { |redis| redis.scard(CONCURRENT_RUNNING_REBALANCES_KEY).to_i } end |
#get_cached_issue_ids(index, limit) ⇒ Object
70 71 72 73 74 |
# File 'lib/gitlab/issues/rebalancing/state.rb', line 70 def get_cached_issue_ids(index, limit) with_redis do |redis| redis.zrange(issue_ids_key, index, index + limit - 1) end end |
#get_current_index ⇒ Object
80 81 82 |
# File 'lib/gitlab/issues/rebalancing/state.rb', line 80 def get_current_index with_redis { |redis| redis.get(current_index_key).to_i } end |
#get_current_project_id ⇒ Object
88 89 90 |
# File 'lib/gitlab/issues/rebalancing/state.rb', line 88 def get_current_project_id with_redis { |redis| redis.get(current_project_key) } end |
#issue_count ⇒ Object
92 93 94 |
# File 'lib/gitlab/issues/rebalancing/state.rb', line 92 def issue_count @issue_count ||= with_redis { |redis| redis.zcard(issue_ids_key) } end |
#rebalance_in_progress? ⇒ Boolean
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/gitlab/issues/rebalancing/state.rb', line 38 def rebalance_in_progress? is_running = case rebalanced_container_type when NAMESPACE namespace_ids = self.class.current_rebalancing_containers.filter_map { |string| string.split("#{NAMESPACE}/").second.to_i } namespace_ids.include?(root_namespace.id) when PROJECT project_ids = self.class.current_rebalancing_containers.filter_map { |string| string.split("#{PROJECT}/").second.to_i } project_ids.include?(projects.take.id) # rubocop:disable CodeReuse/ActiveRecord else false end refresh_keys_expiration if is_running is_running end |
#refresh_keys_expiration ⇒ Object
100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/gitlab/issues/rebalancing/state.rb', line 100 def refresh_keys_expiration with_redis do |redis| Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do redis.pipelined do |pipeline| pipeline.expire(issue_ids_key, REDIS_EXPIRY_TIME) pipeline.expire(current_index_key, REDIS_EXPIRY_TIME) pipeline.expire(current_project_key, REDIS_EXPIRY_TIME) pipeline.expire(CONCURRENT_RUNNING_REBALANCES_KEY, REDIS_EXPIRY_TIME) end end end end |
#remove_current_project_id_cache ⇒ Object
96 97 98 |
# File 'lib/gitlab/issues/rebalancing/state.rb', line 96 def remove_current_project_id_cache with_redis { |redis| redis.del(current_project_key) } end |
#track_new_running_rebalance ⇒ Object
23 24 25 26 27 28 29 30 31 32 |
# File 'lib/gitlab/issues/rebalancing/state.rb', line 23 def track_new_running_rebalance with_redis do |redis| redis.multi do |multi| # we trigger re-balance for namespaces(groups) or specific user project value = "#{rebalanced_container_type}/#{rebalanced_container_id}" multi.sadd?(CONCURRENT_RUNNING_REBALANCES_KEY, value) multi.expire(CONCURRENT_RUNNING_REBALANCES_KEY, REDIS_EXPIRY_TIME) end end end |