worker_roulette 0.1.7 → 0.1.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,184 +1,162 @@
1
1
  require "spec_helper"
2
+ module WorkerRoulette
3
+ describe WorkerRoulette do
4
+ let(:sender) {'katie_80'}
5
+ let(:work_orders) {["hello", "foreman"]}
6
+ let(:default_headers) {Hash['headers' => {'sender' => sender}]}
7
+ let(:hello_work_order) {Hash['payload' => "hello"]}
8
+ let(:foreman_work_order) {Hash['payload' => "foreman"]}
9
+ let(:work_orders_with_headers) {default_headers.merge({'payload' => work_orders})}
10
+ let(:jsonized_work_orders_with_headers) {[WorkerRoulette.dump(work_orders_with_headers)]}
11
+ let(:worker_roulette) { WorkerRoulette.start }
2
12
 
3
- describe WorkerRoulette do
4
- let(:sender) {'katie_80'}
5
- let(:work_orders) {["hello", "foreman"]}
6
- let(:default_headers) {Hash['headers' => {'sender' => sender}]}
7
- let(:hello_work_order) {Hash['payload' => "hello"]}
8
- let(:foreman_work_order) {Hash['payload' => "foreman"]}
9
- let(:work_orders_with_headers) {default_headers.merge({'payload' => work_orders})}
10
- let(:jsonized_work_orders_with_headers) {[WorkerRoulette.dump(work_orders_with_headers)]}
13
+ let(:redis) {Redis.new(worker_roulette.redis_config)}
11
14
 
12
- let(:redis) {Redis.new(WorkerRoulette.redis_config)}
13
-
14
- before do
15
- WorkerRoulette.start
16
- end
17
-
18
- it "should exist" do
19
- expect(WorkerRoulette).not_to be_nil
20
- end
21
-
22
- context Foreman do
23
- let(:subject) {WorkerRoulette.foreman(sender)}
24
-
25
- it "should be working on behalf of a sender" do
26
- expect(subject.sender).to eq(sender)
15
+ it "should exist" do
16
+ expect(worker_roulette).to be_instance_of(WorkerRoulette)
27
17
  end
28
18
 
29
- it "should enqueue_work_order two work_orders in the sender's slot in the switchboard" do
30
- subject.enqueue_work_order(work_orders.first) {}
31
- subject.enqueue_work_order(work_orders.last) {}
32
- expect(redis.lrange(sender, 0, -1)).to eq(work_orders.map {|m| WorkerRoulette.dump(default_headers.merge({'payload' => m})) })
33
- end
34
-
35
- it "should enqueue_work_order an array of work_orders without headers in the sender's slot in the switchboard" do
36
- subject.enqueue_work_order_without_headers(work_orders)
37
- expect(redis.lrange(sender, 0, -1)).to eq([WorkerRoulette.dump(work_orders)])
38
- end
19
+ context Foreman do
20
+ let(:subject) {worker_roulette.foreman(sender)}
39
21
 
40
- it "should enqueue_work_order an array of work_orders with default headers in the sender's slot in the switchboard" do
41
- subject.enqueue_work_order(work_orders)
42
- expect(redis.lrange(sender, 0, -1)).to eq(jsonized_work_orders_with_headers)
43
- end
22
+ it "should be working on behalf of a sender" do
23
+ expect(subject.sender).to eq(sender)
24
+ end
44
25
 
45
- it "should enqueue_work_order an array of work_orders with additional headers in the sender's slot in the switchboard" do
46
- extra_headers = {'foo' => 'bars'}
47
- subject.enqueue_work_order(work_orders, extra_headers)
48
- work_orders_with_headers['headers'].merge!(extra_headers)
49
- expect(redis.lrange(sender, 0, -1)).to eq([WorkerRoulette.dump(work_orders_with_headers)])
50
- end
26
+ it "should enqueue_work_order two work_orders in the sender's work queue" do
27
+ subject.enqueue_work_order(work_orders.first) {}
28
+ subject.enqueue_work_order(work_orders.last) {}
29
+ expect(redis.lrange(sender, 0, -1)).to eq(work_orders.map {|m| WorkerRoulette.dump(default_headers.merge({'payload' => m})) })
30
+ end
51
31
 
52
- it "should post the sender's id to the job board with an order number" do
53
- subject.enqueue_work_order(work_orders.first)
54
- WorkerRoulette.foreman('other_forman').enqueue_work_order(work_orders.last)
55
- expect(redis.zrange(subject.job_board_key, 0, -1, with_scores: true)).to eq([[sender, 1.0], ["other_forman", 2.0]])
56
- end
32
+ it "should enqueue_work_order an array of work_orders without headers in the sender's work queue" do
33
+ subject.enqueue_work_order_without_headers(work_orders)
34
+ expect(redis.lrange(sender, 0, -1)).to eq([WorkerRoulette.dump(work_orders)])
35
+ end
57
36
 
58
- it "should generate a monotically increasing score for senders not on the job board, but not for senders already there" do
59
- other_forman = WorkerRoulette.foreman('other_forman')
60
- expect(redis.get(subject.counter_key)).to be_nil
61
- subject.enqueue_work_order(work_orders.first)
62
- expect(redis.get(subject.counter_key)).to eq("1")
63
- subject.enqueue_work_order(work_orders.last)
64
- expect(redis.get(subject.counter_key)).to eq("1")
65
- other_forman.enqueue_work_order(work_orders.last)
66
- expect(redis.get(other_forman.counter_key)).to eq("2")
67
- end
37
+ it "should enqueue_work_order an array of work_orders with default headers in the sender's work queue" do
38
+ subject.enqueue_work_order(work_orders)
39
+ expect(redis.lrange(sender, 0, -1)).to eq(jsonized_work_orders_with_headers)
40
+ end
68
41
 
69
- it "should publish a notification that a new job is ready" do
70
- result = nil
71
- redis_tradesman = Redis.new
72
- redis_tradesman.subscribe(WorkerRoulette::JOB_NOTIFICATIONS) do |on|
73
- on.subscribe do |channel, subscription|
74
- subject.enqueue_work_order(work_orders)
75
- end
42
+ it "should enqueue_work_order an array of work_orders with additional headers in the sender's work queue" do
43
+ extra_headers = {'foo' => 'bars'}
44
+ subject.enqueue_work_order(work_orders, extra_headers)
45
+ work_orders_with_headers['headers'].merge!(extra_headers)
46
+ expect(redis.lrange(sender, 0, -1)).to eq([WorkerRoulette.dump(work_orders_with_headers)])
47
+ end
76
48
 
77
- on.message do |channel, notification|
78
- result = notification
79
- redis_tradesman.unsubscribe(WorkerRoulette::JOB_NOTIFICATIONS)
80
- end
49
+ it "should post the sender's id to the job board with an order number" do
50
+ subject.enqueue_work_order(work_orders.first)
51
+ worker_roulette.foreman('other_forman').enqueue_work_order(work_orders.last)
52
+ expect(redis.zrange(subject.job_board_key, 0, -1, with_scores: true)).to eq([[sender, 1.0], ["other_forman", 2.0]])
81
53
  end
82
54
 
83
- expect(result).to eq(WorkerRoulette::JOB_NOTIFICATIONS)
55
+ it "should generate a monotically increasing score for senders not on the job board, but not for senders already there" do
56
+ other_forman = worker_roulette.foreman('other_forman')
57
+ expect(redis.get(subject.counter_key)).to be_nil
58
+ subject.enqueue_work_order(work_orders.first)
59
+ expect(redis.get(subject.counter_key)).to eq("1")
60
+ subject.enqueue_work_order(work_orders.last)
61
+ expect(redis.get(subject.counter_key)).to eq("1")
62
+ other_forman.enqueue_work_order(work_orders.last)
63
+ expect(redis.get(other_forman.counter_key)).to eq("2")
64
+ end
84
65
  end
85
- end
86
66
 
87
- context Tradesman do
88
- let(:foreman) {WorkerRoulette.foreman(sender)}
89
- let(:subject) {WorkerRoulette.tradesman}
67
+ context Tradesman do
68
+ let(:foreman) {worker_roulette.foreman(sender)}
69
+ let(:subject) {worker_roulette.tradesman}
90
70
 
91
- before do
92
- foreman.enqueue_work_order(work_orders)
93
- end
71
+ before do
72
+ foreman.enqueue_work_order(work_orders)
73
+ end
94
74
 
95
- it "should have a last sender if it found messages" do
96
- expect(subject.work_orders!.length).to eq(1)
97
- expect(subject.last_sender).to eq(sender)
98
- end
75
+ it "should have a last sender if it found messages" do
76
+ expect(subject.work_orders!.length).to eq(1)
77
+ expect(subject.last_sender).to eq(sender)
78
+ end
99
79
 
100
- it "should not have a last sender if it found no messages" do
101
- expect(subject.work_orders!.length).to eq(1)
102
- expect(subject.work_orders!.length).to eq(0)
103
- expect(subject.last_sender).to be_nil
104
- end
80
+ it "should not have a last sender if it found no messages" do
81
+ expect(subject.work_orders!.length).to eq(1)
82
+ expect(subject.work_orders!.length).to eq(0)
83
+ expect(subject.last_sender).to be_nil
84
+ end
105
85
 
106
- it "should drain one set of work_orders from the sender's slot in the switchboard" do
107
- expect(subject.work_orders!).to eq([work_orders_with_headers])
108
- expect(subject.work_orders!).to be_empty
109
- expect(subject.work_orders!).to be_empty #does not throw an error if queue is already empty
110
- end
86
+ it "should drain one set of work_orders from the sender's work queue" do
87
+ expect(subject.work_orders!).to eq([work_orders_with_headers])
88
+ expect(subject.work_orders!).to be_empty
89
+ expect(subject.work_orders!).to be_empty #does not throw an error if queue is already empty
90
+ end
111
91
 
112
- it "should drain all the work_orders from the sender's slot in the switchboard" do
113
- foreman.enqueue_work_order(work_orders)
114
- expect(subject.work_orders!).to eq([work_orders_with_headers, work_orders_with_headers])
115
- expect(subject.work_orders!).to be_empty
116
- expect(subject.work_orders!).to be_empty #does not throw an error if queue is already empty
117
- end
92
+ it "should drain all the work_orders from the sender's work queue" do
93
+ foreman.enqueue_work_order(work_orders)
94
+ expect(subject.work_orders!).to eq([work_orders_with_headers, work_orders_with_headers])
95
+ expect(subject.work_orders!).to be_empty
96
+ expect(subject.work_orders!).to be_empty #does not throw an error if queue is already empty
97
+ end
118
98
 
119
- it "should take the oldest sender off the job board (FIFO)" do
120
- oldest_sender = sender.to_s
121
- most_recent_sender = 'most_recent_sender'
122
- most_recent_foreman = WorkerRoulette.foreman(most_recent_sender)
123
- most_recent_foreman.enqueue_work_order(work_orders)
124
- expect(redis.zrange(subject.job_board_key, 0, -1)).to eq([oldest_sender, most_recent_sender])
125
- subject.work_orders!
126
- expect(redis.zrange(subject.job_board_key, 0, -1)).to eq([most_recent_sender])
127
- end
99
+ it "should take the oldest sender off the job board (FIFO)" do
100
+ oldest_sender = sender.to_s
101
+ most_recent_sender = 'most_recent_sender'
102
+ most_recent_foreman = worker_roulette.foreman(most_recent_sender)
103
+ most_recent_foreman.enqueue_work_order(work_orders)
104
+ expect(redis.zrange(subject.job_board_key, 0, -1)).to eq([oldest_sender, most_recent_sender])
105
+ subject.work_orders!
106
+ expect(redis.zrange(subject.job_board_key, 0, -1)).to eq([most_recent_sender])
107
+ end
128
108
 
129
- it "should get the work_orders from the next queue when a new job is ready" do
130
- subject.work_orders!
131
- expect(subject).to receive(:work_orders!).twice.and_call_original
109
+ it "should get the work_orders from the next queue when a new job is ready, then poll for new work" do
110
+ subject.work_orders!
111
+ expect(subject).to receive(:work_orders!).and_call_original
112
+ expect(subject.timer).to receive(:after)
132
113
 
133
- publisher = -> {foreman.enqueue_work_order(work_orders); subject.unsubscribe}
114
+ foreman.enqueue_work_order(work_orders)
134
115
 
135
- subject.wait_for_work_orders(publisher) do |redis_work_orders|
136
- expect(redis_work_orders).to eq([work_orders_with_headers])
137
- expect(subject.last_sender).to be_nil
116
+ subject.wait_for_work_orders do |redis_work_orders|
117
+ expect(redis_work_orders).to eq([work_orders_with_headers])
118
+ expect(subject.last_sender).to eq('katie_80')
119
+ end
138
120
  end
139
- end
140
-
141
- it "should publish and subscribe on custom channels" do
142
- tradesman = WorkerRoulette.tradesman('good_channel')
143
- expect(tradesman).to receive(:work_orders!).twice.and_call_original
144
121
 
145
- good_foreman = WorkerRoulette.foreman('foreman', 'good_channel')
146
- bad_foreman = WorkerRoulette.foreman('foreman', 'bad_channel')
122
+ it "should publish and subscribe on custom channels" do
123
+ tradesman = worker_roulette.tradesman('good_channel')
124
+ expect(tradesman).to receive(:work_orders!).and_call_original
147
125
 
126
+ good_foreman = worker_roulette.foreman('foreman', 'good_channel')
127
+ bad_foreman = worker_roulette.foreman('foreman', 'bad_channel')
148
128
 
149
- publish = -> do
150
129
  good_foreman.enqueue_work_order('some old fashion work')
151
130
  bad_foreman.enqueue_work_order('evil biddings you should not carry out')
152
- tradesman.unsubscribe
153
- end
154
131
 
155
- tradesman.wait_for_work_orders(publish) do |work|
156
- expect(work.to_s).to match("some old fashion work")
157
- expect(work.to_s).not_to match("evil")
158
- expect(tradesman.last_sender).to be_nil
132
+ tradesman.wait_for_work_orders do |work|
133
+ expect(work.to_s).to match("some old fashion work")
134
+ expect(work.to_s).not_to match("evil")
135
+ expect(tradesman.last_sender).to eq('foreman')
136
+ end
159
137
  end
160
- end
161
138
 
162
- context "Failure" do
163
- it "should not put the sender_id and work_orders back if processing fails bc new work_orders may have been processed while that process failed" do; end
164
- end
139
+ context "Failure" do
140
+ it "should not put the sender_id and work_orders back if processing fails bc new work_orders may have been processed while that process failed" do; end
141
+ end
165
142
 
166
- context "Concurrent Access" do
167
- it "should pool its connections" do
168
- Array.new(100) do
169
- Thread.new {WorkerRoulette.tradesman_connection_pool.with {|pooled_redis| pooled_redis.get("foo")}}
170
- end.each(&:join)
171
- WorkerRoulette.tradesman_connection_pool.with do |pooled_redis|
172
- expect(pooled_redis.info["connected_clients"].to_i).to be > (WorkerRoulette.pool_size)
143
+ context "Concurrent Access" do
144
+ it "should pool its connections" do
145
+ Array.new(100) do
146
+ Thread.new {worker_roulette.tradesman_connection_pool.with {|pooled_redis| pooled_redis.get("foo")}}
147
+ end.each(&:join)
148
+ worker_roulette.tradesman_connection_pool.with do |pooled_redis|
149
+ expect(pooled_redis.info["connected_clients"].to_i).to be > (worker_roulette.pool_size)
150
+ end
173
151
  end
174
- end
175
152
 
176
- #This may be fixed soon (10 Feb 2014 - https://github.com/redis/redis-rb/pull/389 and https://github.com/redis/redis-rb/issues/364)
177
- it "should not be fork() proof -- forking reconnects need to be handled in the calling code (until redis gem is udpated, then we should be fork-proof)" do
178
- WorkerRoulette.start
179
- WorkerRoulette.tradesman_connection_pool.with {|pooled_redis| pooled_redis.get("foo")}
180
- fork do
181
- expect {WorkerRoulette.tradesman_connection_pool.with {|pooled_redis| pooled_redis.get("foo")}}.to raise_error(Redis::InheritedError)
153
+ #This may be fixed soon (10 Feb 2014 - https://github.com/redis/redis-rb/pull/389 and https://github.com/redis/redis-rb/issues/364)
154
+ it "should not be fork() proof -- forking reconnects need to be handled in the calling code (until redis gem is udpated, then we should be fork-proof)" do
155
+ instance = WorkerRoulette.start
156
+ instance.tradesman_connection_pool.with {|pooled_redis| pooled_redis.get("foo")}
157
+ fork do
158
+ expect {instance.tradesman_connection_pool.with {|pooled_redis| pooled_redis.get("foo")}}.to raise_error(Redis::InheritedError)
159
+ end
182
160
  end
183
161
  end
184
162
  end
data/spec/spec_helper.rb CHANGED
@@ -1,17 +1,18 @@
1
- require 'worker_roulette'
2
- require 'evented-spec'
3
- require 'rspec'
4
- require 'pry'
1
+ module WorkerRoulette
2
+ require 'worker_roulette'
3
+ require 'evented-spec'
4
+ require 'rspec'
5
+ require 'pry'
5
6
 
6
- require File.expand_path(File.join("..", "..", "lib", "worker_roulette.rb"), __FILE__)
7
- include WorkerRoulette
7
+ require File.expand_path(File.join("..", "..", "lib", "worker_roulette.rb"), __FILE__)
8
8
 
9
- Dir[File.join(File.dirname(__FILE__), 'helpers', '**/*.rb')].sort.each { |file| require file.gsub(".rb", "")}
9
+ Dir[File.join(File.dirname(__FILE__), 'helpers', '**/*.rb')].sort.each { |file| require file.gsub(".rb", "")}
10
10
 
11
- EM::Hiredis.reconnect_timeout = 0.01
11
+ EM::Hiredis.reconnect_timeout = 0.01
12
12
 
13
- RSpec.configure do |c|
14
- c.after(:each) do
15
- Redis.new(WorkerRoulette.redis_config).flushdb
13
+ RSpec.configure do |c|
14
+ c.after(:each) do
15
+ Redis.new(WorkerRoulette.start.redis_config).flushdb
16
+ end
16
17
  end
17
- end
18
+ end
@@ -1,23 +1,24 @@
1
1
  require 'spec_helper'
2
2
  module WorkerRoulette
3
- describe "Evented Read Lock" do
3
+ describe "Evented Read Lock" do
4
4
  include EventedSpec::EMSpec
5
5
 
6
- let(:redis) {Redis.new(WorkerRoulette.redis_config)}
6
+ let(:redis) {Redis.new(WorkerRoulette.start.redis_config)}
7
7
  let(:sender) {'katie_80'}
8
8
  let(:work_orders) {"hellot"}
9
9
  let(:lock_key) {"L*:#{sender}"}
10
10
  let(:default_headers) {Hash['headers' => {'sender' => sender}]}
11
11
  let(:work_orders_with_headers) {default_headers.merge({'payload' => work_orders})}
12
12
  let(:jsonized_work_orders_with_headers) {[WorkerRoulette.dump(work_orders_with_headers)]}
13
- let(:foreman) {WorkerRoulette.foreman(sender)}
14
- let(:number_two) {WorkerRoulette.foreman('number_two')}
15
- let(:subject) {WorkerRoulette.tradesman}
16
- let(:subject_two) {WorkerRoulette.tradesman}
13
+ let(:worker_roulette) { WorkerRoulette.start(evented: true) }
14
+ let(:foreman) {worker_roulette.foreman(sender)}
15
+ let(:number_two) {worker_roulette.foreman('number_two')}
16
+ let(:subject) {worker_roulette.tradesman}
17
+ let(:subject_two) {worker_roulette.tradesman}
18
+ let(:lua) { Lua.new(worker_roulette.tradesman_connection_pool) }
17
19
 
18
20
  em_before do
19
- WorkerRoulette.start(evented: true)
20
- Lua.clear_cache!
21
+ lua.clear_cache!
21
22
  redis.script(:flush)
22
23
  redis.flushdb
23
24
  end
@@ -29,9 +30,9 @@ module WorkerRoulette
29
30
  end
30
31
  end
31
32
 
32
- it "should set the lock to expire in 1 second" do
33
+ it "should set the lock to expire in 3 seconds" do
33
34
  evented_readlock_preconditions do
34
- expect(redis.ttl(lock_key)).to eq(1)
35
+ expect(redis.ttl(lock_key)).to eq(3)
35
36
  done
36
37
  end
37
38
  end
@@ -45,13 +46,13 @@ module WorkerRoulette
45
46
  end
46
47
 
47
48
  it "should read from the first available queue that is not locked" do
48
- evented_readlock_preconditions do
49
- foreman.enqueue_work_order(work_orders) do #locked
50
- number_two.enqueue_work_order(work_orders) do #unlocked
49
+ evented_readlock_preconditions do
50
+ foreman.enqueue_work_order(work_orders) do #locked
51
+ number_two.enqueue_work_order(work_orders) do #unlocked
51
52
  subject_two.work_orders!{|work| expect(work.first['headers']['sender']).to eq('number_two'); done}
52
53
  end
53
- end
54
- end
54
+ end
55
+ end
55
56
  end
56
57
 
57
58
  it "should release its last lock when it asks for its next work order from another sender" do
@@ -94,13 +95,13 @@ module WorkerRoulette
94
95
  end
95
96
  end
96
97
  end
97
- end
98
98
 
99
- def evented_readlock_preconditions(&spec_block)
100
- foreman.enqueue_work_order(work_orders) do
101
- subject.work_orders! do |work|
102
- expect(work).to eq([work_orders_with_headers])
103
- spec_block.call
99
+ def evented_readlock_preconditions(&spec_block)
100
+ foreman.enqueue_work_order(work_orders) do
101
+ subject.work_orders! do |work|
102
+ expect(work).to eq([work_orders_with_headers])
103
+ spec_block.call
104
+ end
104
105
  end
105
106
  end
106
107
  end
@@ -2,23 +2,21 @@ require 'spec_helper'
2
2
  module WorkerRoulette
3
3
  describe Lua do
4
4
  include EventedSpec::EMSpec
5
- let(:redis) {Redis.new(WorkerRoulette.redis_config)}
6
-
7
- em_before do
8
- WorkerRoulette.start(evented: true)
9
- end
5
+ let(:worker_roulette) {WorkerRoulette.start(evented: true)}
6
+ let(:lua) { Lua.new(worker_roulette.tradesman_connection_pool) }
7
+ let(:redis) {Redis.new(worker_roulette.redis_config)}
10
8
 
11
9
  before do
12
- Lua.clear_cache!
10
+ lua.clear_cache!
13
11
  redis.script(:flush)
14
12
  redis.flushdb
15
13
  end
16
14
 
17
15
  it "should load and call a lua script" do
18
16
  lua_script = 'return redis.call("SET", KEYS[1], ARGV[1])'
19
- Lua.call(lua_script, ['foo'], ['daddy']) do |result|
20
- expect(Lua.cache.keys.first).to eq(lua_script)
21
- expect(Lua.cache.values.first).to eq(Digest::SHA1.hexdigest(lua_script))
17
+ lua.call(lua_script, ['foo'], ['daddy']) do |result|
18
+ expect(lua.cache.keys.first).to eq(lua_script)
19
+ expect(lua.cache.values.first).to eq(Digest::SHA1.hexdigest(lua_script))
22
20
  expect(result).to eq("OK")
23
21
  done
24
22
  end
@@ -26,12 +24,12 @@ module WorkerRoulette
26
24
 
27
25
  it "should send a sha instead of a script once the script has been cached" do
28
26
  lua_script = 'return KEYS'
29
- expect(Lua).to receive(:eval).and_call_original
27
+ expect(lua).to receive(:eval).and_call_original
30
28
 
31
- Lua.call(lua_script) do |result|
32
- expect(Lua).not_to receive(:eval)
29
+ lua.call(lua_script) do |result|
30
+ expect(lua).not_to receive(:eval)
33
31
 
34
- Lua.call(lua_script) do |inner_result|
32
+ lua.call(lua_script) do |inner_result|
35
33
  expect(inner_result).to be_empty
36
34
  done
37
35
  end
@@ -40,7 +38,7 @@ module WorkerRoulette
40
38
 
41
39
  it "should raise an error to the caller if the script fails in redis" do
42
40
  lua_script = 'this is junk'
43
- # Lua.call(lua_script)
41
+ # lua.call(lua_script)
44
42
  # rspec cannot test this bc of the callbacks, but if you have doubts,
45
43
  # uncomment the line above and watch it fail
46
44
  done
@@ -1,21 +1,22 @@
1
1
  require 'spec_helper'
2
2
  module WorkerRoulette
3
3
  describe "Read Lock" do
4
- let(:redis) {Redis.new(WorkerRoulette.redis_config)}
4
+ let(:worker_roulette) {WorkerRoulette.start(evented: false)}
5
+ let(:redis) {Redis.new(worker_roulette.redis_config)}
5
6
  let(:sender) {'katie_80'}
6
7
  let(:work_orders) {"hellot"}
7
8
  let(:lock_key) {"L*:#{sender}"}
8
9
  let(:default_headers) {Hash['headers' => {'sender' => sender}]}
9
10
  let(:work_orders_with_headers) {default_headers.merge({'payload' => work_orders})}
10
11
  let(:jsonized_work_orders_with_headers) {[WorkerRoulette.dump(work_orders_with_headers)]}
11
- let(:foreman) {WorkerRoulette.foreman(sender)}
12
- let(:number_two) {WorkerRoulette.foreman('number_two')}
13
- let(:subject) {WorkerRoulette.tradesman}
14
- let(:subject_two) {WorkerRoulette.tradesman}
12
+ let(:foreman) {worker_roulette.foreman(sender)}
13
+ let(:number_two) {worker_roulette.foreman('number_two')}
14
+ let(:subject) {worker_roulette.tradesman}
15
+ let(:subject_two) {worker_roulette.tradesman}
16
+ let(:lua) { Lua.new(worker_roulette.tradesman_connection_pool) }
15
17
 
16
18
  before do
17
- WorkerRoulette.start(evented: false)
18
- Lua.clear_cache!
19
+ lua.clear_cache!
19
20
  redis.script(:flush)
20
21
  redis.flushdb
21
22
  foreman.enqueue_work_order(work_orders)
@@ -26,8 +27,8 @@ module WorkerRoulette
26
27
  expect(redis.get(lock_key)).not_to be_nil
27
28
  end
28
29
 
29
- it "should set the lock to expire in 1 second" do
30
- expect(redis.ttl(lock_key)).to eq(1)
30
+ it "should set the lock to expire in 3 second" do
31
+ expect(redis.ttl(lock_key)).to eq(3)
31
32
  end
32
33
 
33
34
  it "should not read a locked queue" do
@@ -66,7 +67,5 @@ module WorkerRoulette
66
67
  expect(subject.work_orders!).to be_empty
67
68
  expect(redis.get(lock_key)).to be_nil
68
69
  end
69
-
70
- pending "pubsub should clean up one contention or remove the lock on the same sender queue automaticly"
71
70
  end
72
71
  end
@@ -23,6 +23,7 @@ Gem::Specification.new do |spec|
23
23
  spec.add_dependency 'em-hiredis', '~> 0.2.1'
24
24
  spec.add_dependency 'connection_pool'
25
25
  spec.add_dependency 'eventmachine', '~> 1.0.3'
26
+ spec.add_dependency 'timers', '~> 3.0.1'
26
27
 
27
28
  spec.add_development_dependency 'bundler'
28
29
  spec.add_development_dependency 'rake'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: worker_roulette
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Saieg
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-09 00:00:00.000000000 Z
11
+ date: 2014-07-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: oj
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - ~>
95
95
  - !ruby/object:Gem::Version
96
96
  version: 1.0.3
97
+ - !ruby/object:Gem::Dependency
98
+ name: timers
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ~>
102
+ - !ruby/object:Gem::Version
103
+ version: 3.0.1
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: 3.0.1
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: bundler
99
113
  requirement: !ruby/object:Gem::Requirement
@@ -236,11 +250,11 @@ files:
236
250
  - README.md
237
251
  - Rakefile
238
252
  - lib/worker_roulette.rb
239
- - lib/worker_roulette/a_tradesman.rb
240
253
  - lib/worker_roulette/foreman.rb
241
254
  - lib/worker_roulette/lua.rb
242
255
  - lib/worker_roulette/tradesman.rb
243
256
  - lib/worker_roulette/version.rb
257
+ - spec/benchmark/irb_demo_runner.rb
244
258
  - spec/benchmark/perf_test.rb
245
259
  - spec/helpers/.gitkeep
246
260
  - spec/integration/evented_worker_roulette_spec.rb
@@ -249,7 +263,6 @@ files:
249
263
  - spec/unit/evented_readlock_spec.rb
250
264
  - spec/unit/lua_spec.rb
251
265
  - spec/unit/readlock_spec.rb
252
- - spec/unit/worker_roulette_spec.rb
253
266
  - worker_roulette.gemspec
254
267
  homepage: https://github.com/nexiahome/worker_roulette
255
268
  licenses: []
@@ -275,6 +288,7 @@ signing_key:
275
288
  specification_version: 4
276
289
  summary: Pub Sub Queue for Redis that ensures ordered processing
277
290
  test_files:
291
+ - spec/benchmark/irb_demo_runner.rb
278
292
  - spec/benchmark/perf_test.rb
279
293
  - spec/helpers/.gitkeep
280
294
  - spec/integration/evented_worker_roulette_spec.rb
@@ -283,4 +297,3 @@ test_files:
283
297
  - spec/unit/evented_readlock_spec.rb
284
298
  - spec/unit/lua_spec.rb
285
299
  - spec/unit/readlock_spec.rb
286
- - spec/unit/worker_roulette_spec.rb
@@ -1,46 +0,0 @@
1
- require_relative './tradesman'
2
- module WorkerRoulette
3
- class ATradesman < Tradesman
4
- attr_reader :timer
5
-
6
- def wait_for_work_orders(on_subscribe_callback = nil, &on_message_callback)
7
- @redis_pubsub ||= WorkerRoulette.new_redis_pubsub #cannot use connection pool bc redis expects each obj to own its own pubsub connection for the life of the subscription
8
- @redis_pubsub.on(:subscribe) {|channel, subscription_count| on_subscribe_callback.call(channel, subscription_count) if on_subscribe_callback}
9
- @redis_pubsub.on(:message) {|channel, message| get_messages(message, channel, on_message_callback)}
10
- set_timer(on_message_callback);
11
- @redis_pubsub.subscribe(@channel)
12
- end
13
-
14
- def unsubscribe(&callback)
15
- deferable = @redis_pubsub.unsubscribe(@channel)
16
- deferable.callback do
17
- @redis_pubsub.close_connection
18
- @redis_pubsub = nil
19
- callback.call
20
- end
21
- deferable.errback do
22
- @redis_pubsub.close_connection
23
- @redis_pubsub = nil
24
- callback.call
25
- end
26
- end
27
-
28
- private
29
-
30
- def get_messages(message, channel, on_message_callback)
31
- return unless on_message_callback
32
- work_orders! do |work_orders_1|
33
- work_orders! do |work_orders|
34
- on_message_callback.call(work_orders_1 + work_orders, message, channel)
35
- end
36
- end
37
- end
38
-
39
- def set_timer(on_message_callback)
40
- return if (@timer || !on_message_callback)
41
- @timer = EM::PeriodicTimer.new(rand(20..25)) do
42
- work_orders! {|work_orders| on_message_callback.call(work_orders, nil, nil)}
43
- end
44
- end
45
- end
46
- end