File: delete_container_repository_worker.rb

package info (click to toggle)
gitlab 17.6.5-19
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 629,368 kB
  • sloc: ruby: 1,915,304; javascript: 557,307; sql: 60,639; xml: 6,509; sh: 4,567; makefile: 1,239; python: 406
file content (100 lines) | stat: -rw-r--r-- 2,946 bytes parent folder | download
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# 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' => '.*',
      'keep_latest' => false,
      '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 update_next_container_repository_status
      end

      next_container_repository.destroy!

      audit_event(next_container_repository)
    rescue StandardError => exception
      update_next_container_repository_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 update_next_container_repository_status
      return unless next_container_repository

      if next_container_repository.failed_deletion_count >= ContainerRepository::MAX_DELETION_FAILURES
        next_container_repository.set_delete_failed_status
      else
        next_container_repository.set_delete_scheduled_status
      end
    end

    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

    def audit_event(repository)
      # defined in EE
    end
  end
end

ContainerRegistry::DeleteContainerRepositoryWorker.prepend_mod