diff --git a/lib/sidekiq_unique_jobs/middleware/server/unique_jobs.rb b/lib/sidekiq_unique_jobs/middleware/server/unique_jobs.rb index cc8ec6251..e8956170f 100644 --- a/lib/sidekiq_unique_jobs/middleware/server/unique_jobs.rb +++ b/lib/sidekiq_unique_jobs/middleware/server/unique_jobs.rb @@ -8,6 +8,7 @@ class UniqueJobs attr_reader :unlock_order, :redis_pool def call(worker, item, _queue, redis_pool = nil) + shutdown = false @redis_pool = redis_pool decide_unlock_order(worker.class) @@ -15,8 +16,11 @@ def call(worker, item, _queue, redis_pool = nil) unlocked = before_yield? ? unlock(lock_key).inspect : 0 yield + rescue Sidekiq::Shutdown + shutdown = true + raise ensure - if after_yield? || !defined? unlocked || unlocked != 1 + if !shutdown && (after_yield? || !defined? unlocked || unlocked != 1) unlock(lock_key) end end diff --git a/spec/lib/middleware/server/unique_jobs_spec.rb b/spec/lib/middleware/server/unique_jobs_spec.rb index 3d54a4fef..cc9ce3a30 100644 --- a/spec/lib/middleware/server/unique_jobs_spec.rb +++ b/spec/lib/middleware/server/unique_jobs_spec.rb @@ -1,4 +1,5 @@ require 'spec_helper' +require 'sidekiq/cli' module SidekiqUniqueJobs module Middleware @@ -75,6 +76,31 @@ module Server expect(subject.default_unlock_order).to eq(:after_yield) end end + + describe '#call' do + context 'unlock' do + let(:uj) { SidekiqUniqueJobs::Middleware::Server::UniqueJobs.new } + let(:items) { [AfterYieldWorker.new, { 'class' => 'testClass' }, 'test'] } + + it 'should unlock after yield when call succeeds' do + expect(uj).to receive(:unlock) + + uj.call(*items) { true } + end + + it 'should unlock after yield when call errors' do + expect(uj).to receive(:unlock) + + expect { uj.call(*items) { fail } }.to raise_error(RuntimeError) + end + + it 'should not unlock after yield on shutdown, but still raise error' do + expect(uj).to_not receive(:unlock) + + expect { uj.call(*items) { fail Sidekiq::Shutdown } }.to raise_error(Sidekiq::Shutdown) + end + end + end end end end diff --git a/spec/support/after_yield_worker.rb b/spec/support/after_yield_worker.rb new file mode 100644 index 000000000..008261505 --- /dev/null +++ b/spec/support/after_yield_worker.rb @@ -0,0 +1,13 @@ +class AfterYieldWorker + include Sidekiq::Worker + sidekiq_options queue: :working, retry: 1, backtrace: 10, unique_unlock_order: :after_yield + sidekiq_options unique: false + + sidekiq_retries_exhausted do |msg| + Sidekiq.logger.warn "Failed #{msg['class']} with #{msg['args']}: #{msg['error_message']}" + end + + def perform(*) + # NO-OP + end +end