Skip to content

Commit

Permalink
Add a requested job
Browse files Browse the repository at this point in the history
Close #121

See readme for more information
  • Loading branch information
mhenrixon committed Oct 8, 2015
1 parent 9c618bc commit 59844f8
Show file tree
Hide file tree
Showing 9 changed files with 78 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
- Remove `unique_lock` and use `unique: ` to set this like in `unique: :until_timeout`
- Warn when using `unique: true` and suggest to change it to what we need with a fallback.
- Create constants for hash keys to avoid having to fix spelling or for renaming keys only having to be done in one place and avoid having to type .freeze everywhere.
- Move all explicit logic out from the server middle ware and make it just call execute on the instance of the lock class (prepare for allowing custom locking classes to be used).

## v4.0.2

Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,20 @@ sidekiq_options unique: :until_timeout

The job won't be unlocked until the timeout/expiry runs out.

### Unique Until And While Executing

```ruby
sidekiq_options unique: :until_and_while_executing
```

This lock is exactly what you would expect. It is considered unique in a way until executing begins and it is locked while executing so what differs from `UntilExecuted`?

The difference is that this job has two types of uniqueness:
1. It is unique until execution
2. It is unique while executing

That means it locks for any job with the same arguments to be persisted into redis and just like you would expect it will only ever allow one job of the same unique arguments to run at any given time but as soon as the runtime lock has been aquired the schedule/async lock is released.

### Uniqueness Scope

- Queue specific locks
Expand Down
1 change: 1 addition & 0 deletions lib/sidekiq_unique_jobs/lock.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
require 'sidekiq_unique_jobs/lock/until_executing'
require 'sidekiq_unique_jobs/lock/while_executing'
require 'sidekiq_unique_jobs/lock/until_timeout'
require 'sidekiq_unique_jobs/lock/until_and_while_executing'

module SidekiqUniqueJobs
module Lock
Expand Down
13 changes: 13 additions & 0 deletions lib/sidekiq_unique_jobs/lock/until_and_while_executing.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module SidekiqUniqueJobs
module Lock
class UntilAndWhileExecuting < UntilExecuting
def execute(callback)
lock = WhileExecuting.new(item, redis_pool)
lock.synchronize do
callback.call if unlock(:server)
yield
end
end
end
end
end
4 changes: 1 addition & 3 deletions lib/sidekiq_unique_jobs/options_with_fallback.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
module SidekiqUniqueJobs
module OptionsWithFallback
def self.included(base)
base.class_exec do
class_attribute :lock_cache
end
base.class_attribute :lock_cache unless base.respond_to?(:lock_cache)
base.lock_cache ||= {}
end

Expand Down
9 changes: 9 additions & 0 deletions spec/jobs/until_and_while_executing_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class UntilAndWhileExecuting
include Sidekiq::Worker

sidekiq_options queue: :working
sidekiq_options unique: :until_and_while_executing

def perform
end
end
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class UntilExecutingWorker
class UntilExecutingJob
include Sidekiq::Worker

sidekiq_options queue: :working
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
require 'spec_helper'

RSpec.describe SidekiqUniqueJobs::Lock::UntilAndWhileExecuting do
let(:item) do
{
'jid' => 'maaaahjid',
'queue' => 'dupsallowed',
'class' => 'UntilAndWhileExecuting',
'unique' => 'until_executed',
'args' => [1]
}
end
let(:callback) { -> {} }
subject { described_class.new(item) }
describe '#execute' do
before { subject.lock(:client) }
let(:runtime_lock) { SidekiqUniqueJobs::Lock::WhileExecuting.new(item, nil) }

it 'unlocks the unique key before yielding' do
expect(SidekiqUniqueJobs::Lock::WhileExecuting).to receive(:new).with(item, nil).and_return(runtime_lock)
expect(callback).to receive(:call)
subject.execute(callback) do

Sidekiq.redis do |c|
expect(c.keys('uniquejobs:*').size).to eq(1)
end

10.times { Sidekiq::Client.push(item) }

Sidekiq.redis do |c|
expect(c.keys('uniquejobs:*').size).to eq(2)
end
end
end
end
end
4 changes: 2 additions & 2 deletions spec/lib/sidekiq_unique_jobs/server/middleware_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ def digest_for(item)

describe ':before_yield' do
it 'removes the lock before yielding to the worker' do
jid = UntilExecutingWorker.perform_async
jid = UntilExecutingJob.perform_async
item = Sidekiq::Queue.new(QUEUE).find_job(jid).item
worker = UntilExecutingWorker.new
worker = UntilExecutingJob.new
subject.call(worker, item, QUEUE) do
Sidekiq.redis do |c|
expect(c.ttl(digest_for(item))).to eq(-2) # key does not exist
Expand Down

0 comments on commit 59844f8

Please sign in to comment.