summaryrefslogtreecommitdiff
path: root/app/workers/container_registry/delete_container_repository_worker.rb
blob: 1f94b1b9e713d0eed138976838427850f904cc66 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# frozen_string_literal: true

module ContainerRegistry
  class DeleteContainerRepositoryWorker
    include ApplicationWorker
    include LimitedCapacity::Worker
    include Gitlab::Utils::StrongMemoize
    extend ::Gitlab::Utils::Override

    data_consistency :always
    queue_namespace :container_repository_delete
    feature_category :container_registry
    urgency :low
    worker_resource_boundary :unknown
    idempotent!

    MAX_CAPACITY = 2
    CLEANUP_TAGS_SERVICE_PARAMS = {
      'name_regex_delete' => '.*',
      'container_expiration_policy' => true # to avoid permissions checks
    }.freeze

    def perform_work
      return unless next_container_repository

      result = delete_tags
      log_delete_tags_service_result(next_container_repository, result)

      if result[:status] == :error || next_container_repository.tags_count != 0
        return next_container_repository.set_delete_scheduled_status
      end

      next_container_repository.destroy!
    rescue StandardError => exception
      next_container_repository&.set_delete_scheduled_status

      Gitlab::ErrorTracking.log_exception(exception, class: self.class.name)
    end

    def remaining_work_count
      ::ContainerRepository.delete_scheduled.limit(max_running_jobs + 1).count
    end

    def max_running_jobs
      MAX_CAPACITY
    end

    private

    def delete_tags
      service = Projects::ContainerRepository::CleanupTagsService.new(
        container_repository: next_container_repository,
        params: CLEANUP_TAGS_SERVICE_PARAMS
      )
      service.execute
    end

    def next_container_repository
      strong_memoize(:next_container_repository) do
        ContainerRepository.transaction do
          # we don't care about the order
          repository = ContainerRepository.next_pending_destruction(order_by: nil)

          repository&.tap(&:set_delete_ongoing_status)
        end
      end
    end

    def log_delete_tags_service_result(container_repository, delete_tags_service_result)
      logger.info(
        structured_payload(
          project_id: container_repository.project_id,
          container_repository_id: container_repository.id,
          container_repository_path: container_repository.path,
          tags_size_before_delete: delete_tags_service_result[:original_size],
          deleted_tags_size: delete_tags_service_result[:deleted_size]
        )
      )
    end
  end
end