diff options
author | Grzegorz Bizon <grzesiek.bizon@gmail.com> | 2016-10-14 11:30:06 +0200 |
---|---|---|
committer | Grzegorz Bizon <grzesiek.bizon@gmail.com> | 2016-10-17 19:47:03 +0200 |
commit | 22ef066862bffc443baf8a630b0752ce37dab01c (patch) | |
tree | 0997fe691ec6bdd003d63d76ce6deb79b258b67d | |
parent | 11485c5acc9247e417838879a31af014972b999c (diff) | |
download | gitlab-ce-22ef066862bffc443baf8a630b0752ce37dab01c.tar.gz |
Avoid race condition when expiring artifacts
It may happen that job meant to remove expired artifacts will be
executed asynchronously when, in the meantime, project associated with
given build gets removed by another asynchronous job. In that case we
should not remove artifacts because such build will be removed anyway,
when project removal is complete.
-rw-r--r-- | app/workers/expire_build_instance_artifacts_worker.rb | 10 | ||||
-rw-r--r-- | spec/workers/expire_build_instance_artifacts_worker_spec.rb | 44 |
2 files changed, 39 insertions, 15 deletions
diff --git a/app/workers/expire_build_instance_artifacts_worker.rb b/app/workers/expire_build_instance_artifacts_worker.rb index 916c2e633c1..d9e2cc37bb3 100644 --- a/app/workers/expire_build_instance_artifacts_worker.rb +++ b/app/workers/expire_build_instance_artifacts_worker.rb @@ -2,10 +2,14 @@ class ExpireBuildInstanceArtifactsWorker include Sidekiq::Worker def perform(build_id) - build = Ci::Build.with_expired_artifacts.reorder(nil).find_by(id: build_id) - return unless build + build = Ci::Build + .with_expired_artifacts + .reorder(nil) + .find_by(id: build_id) - Rails.logger.info "Removing artifacts build #{build.id}..." + return unless build.try(:project) + + Rails.logger.info "Removing artifacts for build #{build.id}..." build.erase_artifacts! end end diff --git a/spec/workers/expire_build_instance_artifacts_worker_spec.rb b/spec/workers/expire_build_instance_artifacts_worker_spec.rb index 2b140f2ba28..d202b3de77e 100644 --- a/spec/workers/expire_build_instance_artifacts_worker_spec.rb +++ b/spec/workers/expire_build_instance_artifacts_worker_spec.rb @@ -6,28 +6,48 @@ describe ExpireBuildInstanceArtifactsWorker do let(:worker) { described_class.new } describe '#perform' do - before { build } - - subject! { worker.perform(build.id) } + before do + worker.perform(build.id) + end context 'with expired artifacts' do - let(:build) { create(:ci_build, :artifacts, artifacts_expire_at: Time.now - 7.days) } + let(:artifacts_expiry) { { artifacts_expire_at: Time.now - 7.days } } - it 'does expire' do - expect(build.reload.artifacts_expired?).to be_truthy - end + context 'when associated project is valid' do + let(:build) do + create(:ci_build, :artifacts, artifacts_expiry) + end - it 'does remove files' do - expect(build.reload.artifacts_file.exists?).to be_falsey + it 'does expire' do + expect(build.reload.artifacts_expired?).to be_truthy + end + + it 'does remove files' do + expect(build.reload.artifacts_file.exists?).to be_falsey + end + + it 'does nullify artifacts_file column' do + expect(build.reload.artifacts_file_identifier).to be_nil + end end - it 'does nullify artifacts_file column' do - expect(build.reload.artifacts_file_identifier).to be_nil + context 'when associated project was removed' do + let(:build) do + create(:ci_build, :artifacts, artifacts_expiry) do |build| + build.project.delete + end + end + + it 'does not remove artifacts' do + expect(build.reload.artifacts_file.exists?).to be_truthy + end end end context 'with not yet expired artifacts' do - let(:build) { create(:ci_build, :artifacts, artifacts_expire_at: Time.now + 7.days) } + let(:build) do + create(:ci_build, :artifacts, artifacts_expire_at: Time.now + 7.days) + end it 'does not expire' do expect(build.reload.artifacts_expired?).to be_falsey |