Commit 01c55ffc authored by Grzegorz Bizon's avatar Grzegorz Bizon

Catch exceptions when stealing background migrations

parent 39b96f02
...@@ -19,7 +19,12 @@ module Gitlab ...@@ -19,7 +19,12 @@ module Gitlab
next unless job.queue == self.queue next unless job.queue == self.queue
next unless migration_class == steal_class next unless migration_class == steal_class
perform(migration_class, migration_args) if job.delete begin
perform(migration_class, migration_args) if job.delete
rescue => e
Logger.new($stdout).warn(e.message)
next
end
end end
end end
end end
......
...@@ -10,40 +10,65 @@ describe Gitlab::BackgroundMigration do ...@@ -10,40 +10,65 @@ describe Gitlab::BackgroundMigration do
describe '.steal' do describe '.steal' do
context 'when there are enqueued jobs present' do context 'when there are enqueued jobs present' do
let(:job) { double(:job, args: ['Foo', [10, 20]]) } let(:queue) do
let(:queue) { [job] } [double(args: ['Foo', [10, 20]], queue: described_class.queue)]
end
before do before do
allow(Sidekiq::Queue).to receive(:new) allow(Sidekiq::Queue).to receive(:new)
.with(described_class.queue) .with(described_class.queue)
.and_return(queue) .and_return(queue)
allow(job).to receive(:queue)
.and_return(described_class.queue)
end end
it 'steals jobs from a queue' do context 'when queue contains unprocessed jobs' do
expect(queue[0]).to receive(:delete).and_return(true) it 'steals jobs from a queue' do
expect(queue[0]).to receive(:delete).and_return(true)
expect(described_class).to receive(:perform).with('Foo', [10, 20]) expect(described_class).to receive(:perform).with('Foo', [10, 20])
described_class.steal('Foo') described_class.steal('Foo')
end end
it 'does not steal job that has already been taken' do
expect(queue[0]).to receive(:delete).and_return(false)
expect(described_class).not_to receive(:perform).with('Foo', [10, 20])
described_class.steal('Foo')
end
it 'does not steal job that has already been taken' do it 'does not steal jobs for a different migration' do
expect(queue[0]).to receive(:delete).and_return(false) expect(described_class).not_to receive(:perform)
expect(described_class).not_to receive(:perform).with('Foo', [10, 20]) expect(queue[0]).not_to receive(:delete)
described_class.steal('Foo') described_class.steal('Bar')
end
end end
it 'does not steal jobs for a different migration' do context 'when one of the jobs raises an error' do
expect(described_class).not_to receive(:perform) let(:migration) { spy(:migration) }
let(:queue) do
[double(args: ['Foo', [10, 20]], queue: described_class.queue),
double(args: ['Foo', [20, 30]], queue: described_class.queue)]
end
before do
stub_const("#{described_class}::Foo", migration)
expect(queue[0]).not_to receive(:delete) allow(migration).to receive(:perform).with(10, 20)
.and_raise(StandardError, 'Migration error')
described_class.steal('Bar') allow(queue[0]).to receive(:delete).and_return(true)
allow(queue[1]).to receive(:delete).and_return(true)
end
it 'recovers from an exceptions and continues' do
expect(migration).to receive(:perform).twice
expect { described_class.steal('Foo') }
.to output(/Migration error/).to_stdout
end
end end
end end
......
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