debian-mirror-gitlab/app/services/ci/job_artifacts/destroy_batch_service.rb

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

153 lines
5.1 KiB
Ruby
Raw Normal View History

2021-04-29 21:17:54 +05:30
# frozen_string_literal: true
module Ci
module JobArtifacts
class DestroyBatchService
include BaseServiceUtility
include ::Gitlab::Utils::StrongMemoize
# Danger: Private - Should only be called in Ci Services that pass a batch of job artifacts
# Not for use outside of the Ci:: namespace
# Adds the passed batch of job artifacts to the `ci_deleted_objects` table
# for asyncronous destruction of the objects in Object Storage via the `Ci::DeleteObjectsService`
# and then deletes the batch of related `ci_job_artifacts` records.
# Params:
# +job_artifacts+:: A relation of job artifacts to destroy (fewer than MAX_JOB_ARTIFACT_BATCH_SIZE)
# +pick_up_at+:: When to pick up for deletion of files
# Returns:
# +Hash+:: A hash with status and destroyed_artifacts_count keys
2023-01-13 00:05:48 +05:30
def initialize(job_artifacts, pick_up_at: nil, skip_projects_on_refresh: false)
2021-04-29 21:17:54 +05:30
@job_artifacts = job_artifacts.with_destroy_preloads.to_a
@pick_up_at = pick_up_at
2022-07-23 23:45:48 +05:30
@skip_projects_on_refresh = skip_projects_on_refresh
2023-05-27 22:25:52 +05:30
@destroyed_ids = []
2021-04-29 21:17:54 +05:30
end
# rubocop: disable CodeReuse/ActiveRecord
2021-06-08 01:23:25 +05:30
def execute(update_stats: true)
2022-07-23 23:45:48 +05:30
if @skip_projects_on_refresh
exclude_artifacts_undergoing_stats_refresh
else
track_artifacts_undergoing_stats_refresh
end
2023-05-27 22:25:52 +05:30
if @job_artifacts.empty?
return success(destroyed_ids: @destroyed_ids, destroyed_artifacts_count: 0, statistics_updates: {})
end
2021-04-29 21:17:54 +05:30
2021-12-11 22:18:48 +05:30
destroy_related_records(@job_artifacts)
2022-07-16 23:28:13 +05:30
destroy_around_hook(@job_artifacts) do
2023-05-27 22:25:52 +05:30
@destroyed_ids = @job_artifacts.map(&:id)
2022-07-16 23:28:13 +05:30
Ci::DeletedObject.transaction do
Ci::DeletedObject.bulk_import(@job_artifacts, @pick_up_at)
2023-05-27 22:25:52 +05:30
Ci::JobArtifact.id_in(@destroyed_ids).delete_all
2022-07-16 23:28:13 +05:30
end
2021-04-29 21:17:54 +05:30
end
2021-12-11 22:18:48 +05:30
after_batch_destroy_hook(@job_artifacts)
2021-06-08 01:23:25 +05:30
update_project_statistics! if update_stats
2023-03-17 16:20:25 +05:30
2021-12-11 22:18:48 +05:30
increment_monitoring_statistics(artifacts_count, artifacts_bytes)
2021-04-29 21:17:54 +05:30
2022-08-27 11:52:29 +05:30
Gitlab::Ci::Artifacts::Logger.log_deleted(@job_artifacts, 'Ci::JobArtifacts::DestroyBatchService#execute')
2023-05-27 22:25:52 +05:30
success(
destroyed_ids: @destroyed_ids,
destroyed_artifacts_count: artifacts_count,
statistics_updates: statistics_updates_per_project
)
2021-04-29 21:17:54 +05:30
end
# rubocop: enable CodeReuse/ActiveRecord
private
2022-07-16 23:28:13 +05:30
# Overriden in EE
# :nocov:
def destroy_around_hook(artifacts)
yield
end
# :nocov:
2021-12-11 22:18:48 +05:30
# Overriden in EE
2021-04-29 21:17:54 +05:30
def destroy_related_records(artifacts); end
2021-12-11 22:18:48 +05:30
# Overriden in EE
def after_batch_destroy_hook(artifacts); end
2021-06-08 01:23:25 +05:30
# using ! here since this can't be called inside a transaction
def update_project_statistics!
2023-03-17 16:20:25 +05:30
statistics_updates_per_project.each do |project, increments|
ProjectStatistics.bulk_increment_statistic(project, Ci::JobArtifact.project_statistics_name, increments)
2021-06-08 01:23:25 +05:30
end
end
2023-03-17 16:20:25 +05:30
def statistics_updates_per_project
strong_memoize(:statistics_updates_per_project) do
result = Hash.new { |updates, project| updates[project] = [] }
@job_artifacts.each_with_object(result) do |job_artifact, result|
increment = Gitlab::Counters::Increment.new(amount: -job_artifact.size.to_i, ref: job_artifact.id)
result[job_artifact.project] << increment
2021-06-08 01:23:25 +05:30
end
2021-04-29 21:17:54 +05:30
end
end
2021-12-11 22:18:48 +05:30
def increment_monitoring_statistics(size, bytes)
metrics.increment_destroyed_artifacts_count(size)
metrics.increment_destroyed_artifacts_bytes(bytes)
2021-04-29 21:17:54 +05:30
end
def metrics
@metrics ||= ::Gitlab::Ci::Artifacts::Metrics.new
end
def artifacts_count
strong_memoize(:artifacts_count) do
@job_artifacts.count
end
end
2021-12-11 22:18:48 +05:30
def artifacts_bytes
strong_memoize(:artifacts_bytes) do
@job_artifacts.sum { |artifact| artifact.try(:size) || 0 }
end
end
2022-04-01 21:47:47 +05:30
2022-07-23 23:45:48 +05:30
def track_artifacts_undergoing_stats_refresh
project_ids = @job_artifacts.find_all do |artifact|
artifact.project.refreshing_build_artifacts_size?
end.map(&:project_id).uniq
project_ids.each do |project_id|
Gitlab::ProjectStatsRefreshConflictsLogger.warn_artifact_deletion_during_stats_refresh(
method: 'Ci::JobArtifacts::DestroyBatchService#execute',
project_id: project_id
)
end
end
def exclude_artifacts_undergoing_stats_refresh
project_ids = Set.new
@job_artifacts.reject! do |artifact|
next unless artifact.project.refreshing_build_artifacts_size?
project_ids << artifact.project_id
end
2022-08-13 15:12:31 +05:30
if project_ids.any?
Gitlab::ProjectStatsRefreshConflictsLogger.warn_skipped_artifact_deletion_during_stats_refresh(
method: 'Ci::JobArtifacts::DestroyBatchService#execute',
project_ids: project_ids
)
end
2022-07-23 23:45:48 +05:30
end
2021-04-29 21:17:54 +05:30
end
end
end
2021-06-08 01:23:25 +05:30
Ci::JobArtifacts::DestroyBatchService.prepend_mod_with('Ci::JobArtifacts::DestroyBatchService')