summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorShinya Maeda <shinya@gitlab.com>2019-01-17 15:06:37 +0900
committerShinya Maeda <shinya@gitlab.com>2019-01-24 20:50:42 +0900
commit3cc3650dfee5132c120b2b418918f12b3eebcde2 (patch)
tree0497feec4829ed16e0b0d37954b0998a4d8fac15 /app
parent490eeb5159945107576c756b22c08f99b45a8463 (diff)
downloadgitlab-ce-3cc3650dfee5132c120b2b418918f12b3eebcde2.tar.gz
Remove expired artifacts periodically
Rename Introduce Destroy expired job artifacts service Revert a bit Add changelog Use expired Improve Fix spec Fix spec Use bang for destroy Introduce iteration limit Update comment Simplify more Refacor Remove unnecessary thing Fix comments Fix coding offence Make loop helper exception free
Diffstat (limited to 'app')
-rw-r--r--app/models/ci/job_artifact.rb2
-rw-r--r--app/services/ci/destroy_expired_job_artifacts_service.rb38
-rw-r--r--app/workers/expire_build_artifacts_worker.rb14
3 files changed, 53 insertions, 1 deletions
diff --git a/app/models/ci/job_artifact.rb b/app/models/ci/job_artifact.rb
index 11c88200c37..789bb293811 100644
--- a/app/models/ci/job_artifact.rb
+++ b/app/models/ci/job_artifact.rb
@@ -73,6 +73,8 @@ module Ci
where(file_type: types)
end
+ scope :expired, -> (limit) { where('expire_at < ?', Time.now).limit(limit) }
+
delegate :filename, :exists?, :open, to: :file
enum file_type: {
diff --git a/app/services/ci/destroy_expired_job_artifacts_service.rb b/app/services/ci/destroy_expired_job_artifacts_service.rb
new file mode 100644
index 00000000000..7d2f5d33fed
--- /dev/null
+++ b/app/services/ci/destroy_expired_job_artifacts_service.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+module Ci
+ class DestroyExpiredJobArtifactsService
+ include ::Gitlab::ExclusiveLeaseHelpers
+ include ::Gitlab::LoopHelpers
+
+ BATCH_SIZE = 100
+ LOOP_TIMEOUT = 45.minutes
+ LOOP_LIMIT = 1000
+ EXCLUSIVE_LOCK_KEY = 'expired_job_artifacts:destroy:lock'
+ LOCK_TIMEOUT = 50.minutes
+
+ ##
+ # Destroy expired job artifacts on GitLab instance
+ #
+ # This destroy process cannot run for more than 45 minutes. This is for
+ # preventing multiple `ExpireBuildArtifactsWorker` CRON jobs run concurrently,
+ # which is scheduled at every hour.
+ def execute
+ in_lock(EXCLUSIVE_LOCK_KEY, ttl: LOCK_TIMEOUT, retries: 1) do
+ loop_until(timeout: LOOP_TIMEOUT, limit: LOOP_LIMIT) do
+ destroy_batch
+ end
+ end
+ end
+
+ private
+
+ def destroy_batch
+ artifacts = Ci::JobArtifact.expired(BATCH_SIZE).to_a
+
+ return false if artifacts.empty?
+
+ artifacts.each(&:destroy!)
+ end
+ end
+end
diff --git a/app/workers/expire_build_artifacts_worker.rb b/app/workers/expire_build_artifacts_worker.rb
index dce812d1ae2..251e95c68d5 100644
--- a/app/workers/expire_build_artifacts_worker.rb
+++ b/app/workers/expire_build_artifacts_worker.rb
@@ -4,8 +4,20 @@ class ExpireBuildArtifactsWorker
include ApplicationWorker
include CronjobQueue
- # rubocop: disable CodeReuse/ActiveRecord
def perform
+ if Feature.enabled?(:ci_new_expire_job_artifacts_service, default_enabled: true)
+ perform_efficient_artifacts_removal
+ else
+ perform_legacy_artifacts_removal
+ end
+ end
+
+ def perform_efficient_artifacts_removal
+ Ci::DestroyExpiredJobArtifactsService.new.execute
+ end
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def perform_legacy_artifacts_removal
Rails.logger.info 'Scheduling removal of build artifacts'
build_ids = Ci::Build.with_expired_artifacts.pluck(:id)