diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-03-16 20:35:23 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-03-16 20:35:23 +0300 |
commit | 67531b6892b1effd47b40d0c35b583dd586faa72 (patch) | |
tree | 409a4d8251ac95e41e0f89bbd92254e1cbcb436d /app/services | |
parent | 3562e58c753b662e5ec0b7b042fbbd5d49907aa8 (diff) |
Add latest changes from gitlab-org/gitlab@14-8-stable-ee
Diffstat (limited to 'app/services')
-rw-r--r-- | app/services/ci/job_artifacts/destroy_associations_service.rb | 2 | ||||
-rw-r--r-- | app/services/ci/job_artifacts/destroy_batch_service.rb | 56 |
2 files changed, 56 insertions, 2 deletions
diff --git a/app/services/ci/job_artifacts/destroy_associations_service.rb b/app/services/ci/job_artifacts/destroy_associations_service.rb index 794d24eadf2..08d7f7f6f02 100644 --- a/app/services/ci/job_artifacts/destroy_associations_service.rb +++ b/app/services/ci/job_artifacts/destroy_associations_service.rb @@ -12,7 +12,7 @@ module Ci def destroy_records @job_artifacts_relation.each_batch(of: BATCH_SIZE) do |relation| - service = Ci::JobArtifacts::DestroyBatchService.new(relation, pick_up_at: Time.current) + service = Ci::JobArtifacts::DestroyBatchService.new(relation, pick_up_at: Time.current, fix_expire_at: false) result = service.execute(update_stats: false) updates = result[:statistics_updates] diff --git a/app/services/ci/job_artifacts/destroy_batch_service.rb b/app/services/ci/job_artifacts/destroy_batch_service.rb index 866b40c32d8..d5a0a2dd885 100644 --- a/app/services/ci/job_artifacts/destroy_batch_service.rb +++ b/app/services/ci/job_artifacts/destroy_batch_service.rb @@ -17,13 +17,18 @@ module Ci # +pick_up_at+:: When to pick up for deletion of files # Returns: # +Hash+:: A hash with status and destroyed_artifacts_count keys - def initialize(job_artifacts, pick_up_at: nil) + def initialize(job_artifacts, pick_up_at: nil, fix_expire_at: fix_expire_at?) @job_artifacts = job_artifacts.with_destroy_preloads.to_a @pick_up_at = pick_up_at + @fix_expire_at = fix_expire_at end # rubocop: disable CodeReuse/ActiveRecord def execute(update_stats: true) + # Detect and fix artifacts that had `expire_at` wrongly backfilled by migration + # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/47723 + detect_and_fix_wrongly_expired_artifacts + return success(destroyed_artifacts_count: 0, statistics_updates: {}) if @job_artifacts.empty? destroy_related_records(@job_artifacts) @@ -89,6 +94,55 @@ module Ci @job_artifacts.sum { |artifact| artifact.try(:size) || 0 } end end + + # This detects and fixes job artifacts that have `expire_at` wrongly backfilled by the migration + # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/47723. + # These job artifacts will not be deleted and will have their `expire_at` removed. + # + # The migration would have backfilled `expire_at` + # to midnight on the 22nd of the month of the local timezone, + # storing it as UTC time in the database. + # + # If the timezone setting has changed since the migration, + # the `expire_at` stored in the database could have changed to a different local time other than midnight. + # For example: + # - changing timezone from UTC+02:00 to UTC+02:30 would change the `expire_at` in local time 00:00:00 to 00:30:00. + # - changing timezone from UTC+00:00 to UTC-01:00 would change the `expire_at` in local time 00:00:00 to 23:00:00 on the previous day (21st). + # + # Therefore job artifacts that have `expire_at` exactly on the 00, 30 or 45 minute mark + # on the dates 21, 22, 23 of the month will not be deleted. + # https://en.wikipedia.org/wiki/List_of_UTC_time_offsets + def detect_and_fix_wrongly_expired_artifacts + return unless @fix_expire_at + + wrongly_expired_artifacts, @job_artifacts = @job_artifacts.partition { |artifact| wrongly_expired?(artifact) } + + remove_expire_at(wrongly_expired_artifacts) + end + + def fix_expire_at? + Feature.enabled?(:ci_detect_wrongly_expired_artifacts, default_enabled: :yaml) + end + + def wrongly_expired?(artifact) + return false unless artifact.expire_at.present? + + match_date?(artifact.expire_at) && match_time?(artifact.expire_at) + end + + def match_date?(expire_at) + [21, 22, 23].include?(expire_at.day) + end + + def match_time?(expire_at) + %w[00:00.000 30:00.000 45:00.000].include?(expire_at.strftime('%M:%S.%L')) + end + + def remove_expire_at(artifacts) + Ci::JobArtifact.id_in(artifacts).update_all(expire_at: nil) + + Gitlab::AppLogger.info(message: "Fixed expire_at from artifacts.", fixed_artifacts_expire_at_count: artifacts.count) + end end end end |