orphan_job_artifact_files_batch.rb 1.91 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
# frozen_string_literal: true

module Gitlab
  module Cleanup
    class OrphanJobArtifactFilesBatch
      BatchFull = Class.new(StandardError)

      class ArtifactFile
        attr_accessor :path

        def initialize(path)
          @path = path
        end

        def artifact_id
          path.split('/').last.to_i
        end
      end

      include Gitlab::Utils::StrongMemoize

      attr_reader :batch_size, :dry_run
      attr_accessor :artifact_files

25
      def initialize(batch_size:, dry_run: true, logger: Rails.logger) # rubocop:disable Gitlab/RailsLogger
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
        @batch_size = batch_size
        @dry_run = dry_run
        @logger = logger
        @artifact_files = []
      end

      def clean!
        return if artifact_files.empty?

        lost_and_found.each do |artifact|
          clean_one!(artifact)
        end
      end

      def full?
        artifact_files.count >= batch_size
      end

      def <<(artifact_path)
        raise BatchFull, "Batch full! Already contains #{artifact_files.count} artifacts" if full?

        artifact_files << ArtifactFile.new(artifact_path)
      end

      def lost_and_found
        strong_memoize(:lost_and_found) do
          artifact_file_ids = artifact_files.map(&:artifact_id)
          existing_artifact_ids = ::Ci::JobArtifact.id_in(artifact_file_ids).pluck_primary_key

          artifact_files.reject { |artifact| existing_artifact_ids.include?(artifact.artifact_id) }
        end
      end

      private

      def clean_one!(artifact_file)
        log_debug("Found orphan job artifact file @ #{artifact_file.path}")

        remove_file!(artifact_file) unless dry_run
      end

      def remove_file!(artifact_file)
        FileUtils.rm_rf(artifact_file.path)
      end

      def log_info(msg, params = {})
        @logger.info("#{'[DRY RUN]' if dry_run} #{msg}")
      end

      def log_debug(msg, params = {})
        @logger.debug(msg)
      end
    end
  end
end