2020-09-04 11:08:46 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
class IssuePlacementWorker
|
|
|
|
include ApplicationWorker
|
|
|
|
|
2021-04-30 14:10:09 -04:00
|
|
|
sidekiq_options retry: 3
|
|
|
|
|
2020-09-04 11:08:46 -04:00
|
|
|
idempotent!
|
2021-04-26 08:09:44 -04:00
|
|
|
deduplicate :until_executed, including_scheduled: true
|
2020-09-04 11:08:46 -04:00
|
|
|
feature_category :issue_tracking
|
|
|
|
urgency :high
|
|
|
|
worker_resource_boundary :cpu
|
|
|
|
weight 2
|
|
|
|
|
|
|
|
# Move at most the most recent 100 issues
|
|
|
|
QUERY_LIMIT = 100
|
|
|
|
|
|
|
|
# rubocop: disable CodeReuse/ActiveRecord
|
2020-09-15 08:09:30 -04:00
|
|
|
def perform(issue_id, project_id = nil)
|
2020-09-16 08:10:15 -04:00
|
|
|
issue = find_issue(issue_id, project_id)
|
2020-09-04 11:08:46 -04:00
|
|
|
return unless issue
|
|
|
|
|
2021-05-17 14:10:42 -04:00
|
|
|
# Temporary disable moving null elements because of performance problems
|
|
|
|
# For more information check https://gitlab.com/gitlab-com/gl-infra/production/-/issues/4321
|
|
|
|
return if issue.blocked_for_repositioning?
|
|
|
|
|
2020-09-11 02:08:45 -04:00
|
|
|
# Move the oldest 100 unpositioned items to the end.
|
2020-09-04 11:08:46 -04:00
|
|
|
# This is to deal with out-of-order execution of the worker,
|
|
|
|
# while preserving creation order.
|
|
|
|
to_place = Issue
|
|
|
|
.relative_positioning_query_base(issue)
|
|
|
|
.where(relative_position: nil)
|
2020-09-11 02:08:45 -04:00
|
|
|
.order({ created_at: :asc }, { id: :asc })
|
|
|
|
.limit(QUERY_LIMIT + 1)
|
|
|
|
.to_a
|
2020-09-04 11:08:46 -04:00
|
|
|
|
2020-09-11 02:08:45 -04:00
|
|
|
leftover = to_place.pop if to_place.count > QUERY_LIMIT
|
|
|
|
|
|
|
|
Issue.move_nulls_to_end(to_place)
|
2021-05-11 23:10:21 -04:00
|
|
|
Issues::BaseService.new(project: nil).rebalance_if_needed(to_place.max_by(&:relative_position))
|
2020-09-16 08:10:15 -04:00
|
|
|
IssuePlacementWorker.perform_async(nil, leftover.project_id) if leftover.present?
|
2020-09-04 11:08:46 -04:00
|
|
|
rescue RelativePositioning::NoSpaceLeft => e
|
2020-09-16 08:10:15 -04:00
|
|
|
Gitlab::ErrorTracking.log_exception(e, issue_id: issue_id, project_id: project_id)
|
2021-05-19 14:10:39 -04:00
|
|
|
IssueRebalancingWorker.perform_async(nil, *root_namespace_id_to_rebalance(issue, project_id))
|
2020-09-04 11:08:46 -04:00
|
|
|
end
|
2020-09-16 08:10:15 -04:00
|
|
|
|
|
|
|
def find_issue(issue_id, project_id)
|
2020-09-24 14:09:51 -04:00
|
|
|
return Issue.id_in(issue_id).take if issue_id
|
2020-09-16 08:10:15 -04:00
|
|
|
|
2020-09-24 14:09:51 -04:00
|
|
|
project = Project.id_in(project_id).take
|
2020-09-16 08:10:15 -04:00
|
|
|
return unless project
|
|
|
|
|
2020-09-24 14:09:51 -04:00
|
|
|
project.issues.take
|
2020-09-16 08:10:15 -04:00
|
|
|
end
|
2020-09-24 14:09:51 -04:00
|
|
|
# rubocop: enable CodeReuse/ActiveRecord
|
2021-05-19 14:10:39 -04:00
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def root_namespace_id_to_rebalance(issue, project_id)
|
|
|
|
project_id = project_id.presence || issue.project_id
|
|
|
|
Project.find(project_id)&.self_or_root_group_ids
|
|
|
|
end
|
2020-09-04 11:08:46 -04:00
|
|
|
end
|