Commit 22ef0668 authored by Grzegorz Bizon's avatar Grzegorz Bizon

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.
parent 11485c5a
...@@ -2,10 +2,14 @@ class ExpireBuildInstanceArtifactsWorker ...@@ -2,10 +2,14 @@ class ExpireBuildInstanceArtifactsWorker
include Sidekiq::Worker include Sidekiq::Worker
def perform(build_id) def perform(build_id)
build = Ci::Build.with_expired_artifacts.reorder(nil).find_by(id: build_id) build = Ci::Build
return unless 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! build.erase_artifacts!
end end
end end
...@@ -6,28 +6,48 @@ describe ExpireBuildInstanceArtifactsWorker do ...@@ -6,28 +6,48 @@ describe ExpireBuildInstanceArtifactsWorker do
let(:worker) { described_class.new } let(:worker) { described_class.new }
describe '#perform' do describe '#perform' do
before { build } before do
worker.perform(build.id)
subject! { worker.perform(build.id) } end
context 'with expired artifacts' do 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 context 'when associated project is valid' do
expect(build.reload.artifacts_expired?).to be_truthy let(:build) do
end create(:ci_build, :artifacts, artifacts_expiry)
end
it 'does remove files' do it 'does expire' do
expect(build.reload.artifacts_file.exists?).to be_falsey 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 end
it 'does nullify artifacts_file column' do context 'when associated project was removed' do
expect(build.reload.artifacts_file_identifier).to be_nil 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
end end
context 'with not yet expired artifacts' do 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 it 'does not expire' do
expect(build.reload.artifacts_expired?).to be_falsey expect(build.reload.artifacts_expired?).to be_falsey
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment