1
0
Fork 0
mirror of https://github.com/mperham/sidekiq.git synced 2022-11-09 13:52:34 -05:00

add unique payloads support, addresses issue #4

This commit is contained in:
Ryan LeCompte 2012-02-07 03:29:09 -08:00
parent 2d42f3df42
commit 62045af3d5
4 changed files with 48 additions and 4 deletions

View file

@ -1,9 +1,14 @@
require 'multi_json'
require 'redis'
require 'base64'
module Sidekiq
class Client
class << self
attr_accessor :push_unique_only
end
def self.redis
@redis ||= begin
# autoconfig for Heroku
@ -24,7 +29,16 @@ module Sidekiq
raise(ArgumentError, "Message must include a class and set of arguments: #{item.inspect}") if !item['class'] || !item['args']
item['class'] = item['class'].to_s if !item['class'].is_a?(String)
redis.rpush("queue:#{queue}", MultiJson.encode(item))
queue_key = "queue:#{queue}"
encoded_payloads_key = "queue:encoded:#{queue}"
payload = MultiJson.encode(item)
encoded_payload = Base64.encode64(payload)
return if push_unique_only && already_queued?(encoded_payloads_key, encoded_payload)
redis.multi do
redis.sadd(encoded_payloads_key, encoded_payload)
redis.rpush(queue_key, payload)
end
end
# Please use .push if possible instead.
@ -44,5 +58,9 @@ module Sidekiq
queue = (klass.respond_to?(:queue) && klass.queue) || 'default'
push(queue, { 'class' => klass.name, 'args' => args })
end
def self.already_queued?(queue_key, encoded_payload)
redis.sismember(queue_key, encoded_payload)
end
end
end

View file

@ -83,11 +83,15 @@ module Sidekiq
def find_work(queue_idx)
current_queue = @queues[queue_idx]
msg = @redis.lpop("queue:#{current_queue}")
queue_key = "queue:#{current_queue}"
encoded_payloads_key = "queue:encoded:#{current_queue}"
msg = @redis.lpop(queue_key)
if msg
payload = MultiJson.decode(msg)
@redis.srem(encoded_payloads_key, Base64.encode64(msg))
processor = @ready.pop
@busy << processor
processor.process! MultiJson.decode(msg)
processor.process!(payload)
end
!!msg
end

View file

@ -3,10 +3,32 @@ require 'sidekiq/client'
require 'sidekiq/worker'
class TestClient < MiniTest::Unit::TestCase
describe 'with real redis' do
before do
Sidekiq::Client.redis = Redis.connect(:url => 'redis://localhost/sidekiq_test')
Sidekiq::Client.redis.flushdb
end
it 'does not push duplicate messages when configured for unique only' do
Sidekiq::Client.push_unique_only = true
10.times { Sidekiq::Client.push('customqueue', 'class' => 'Foo', 'args' => [1, 2]) }
assert_equal Sidekiq::Client.redis.llen("queue:customqueue"), 1
end
it 'does push duplicate messages when not configured for unique only' do
Sidekiq::Client.push_unique_only = false
10.times { Sidekiq::Client.push('customqueue2', 'class' => 'Foo', 'args' => [1, 2]) }
assert_equal Sidekiq::Client.redis.llen("queue:customqueue2"), 10
end
end
describe 'with mock redis' do
before do
@redis = MiniTest::Mock.new
def @redis.multi; yield; end
def @redis.sadd(*); true; end
Sidekiq::Client.redis = @redis
Sidekiq::Client.push_unique_only = false
end
it 'raises ArgumentError with invalid params' do

View file

@ -30,7 +30,7 @@ class TestManager < MiniTest::Unit::TestCase
q << 'done' if $processed == 2
end
mgr.start!
result = q.timed_pop
result = q.timed_pop(1.0)
assert_equal 'done', result
mgr.stop
end