worker_roulette 0.1.9 → 0.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -13
- data/.agignore +2 -0
- data/lib/worker_roulette/foreman.rb +24 -24
- data/lib/worker_roulette/lua.rb +4 -4
- data/lib/worker_roulette/tradesman.rb +117 -58
- data/lib/worker_roulette/version.rb +1 -1
- data/spec/integration/evented_worker_roulette_spec.rb +23 -0
- data/spec/integration/worker_roulette_spec.rb +65 -33
- data/worker_roulette.gemspec +14 -17
- metadata +63 -104
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
MDNhZWRmYjVkOWQ1MGEwYjk3NmQ5Njg5YjViMzIwZWFkYzU5NjMxMA==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 18fac5a135506a2e24d37a0d7c64a5e38deb5958
|
4
|
+
data.tar.gz: 8805d12a5a60b90353baf73a459399e41c0a7254
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
MzQ4NmVlYTU5ZjU2MGZmNWVhYTg5NDRiNWRlZTBlNzMxZDk2ZWE4OTE1OTg2
|
11
|
-
Y2Q1OTBhMmVhN2IwNmQ3OGQ3ZDA1MTI4MDdmMzA1MWJkZTZkYzc=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
Y2I0ZGFkOTI2OGNjODA5M2NmMTQxM2Q2MTNhN2IzMTVlZDZkNWI1ZjU2Nzll
|
14
|
-
OTUxNjhkOTFjYzU4NzQ3OTU5OTMxYjI3OGZmY2NiMzlhNmM0NTMwYTg5ZGZj
|
15
|
-
ZGE5MjliZWI0MTE2MjAzMWM5MTY3ODhmMzhlYjYyMmNhZTdjYWM=
|
6
|
+
metadata.gz: a924c28f238c090ceaaab24ce7c0d1c247711f0e253c1ab63ede4b8515fc7eddf2d1139aba6c8abf570d2c0270a1bba3c772dd3eee9c78826f63197b65220eb5
|
7
|
+
data.tar.gz: 9e8dc7891d83aad2e8ed176a25588cd0fd32ee853e7b7819cb21afdf8eab311184ccd52c5133d36e72e87ec6fe323c25051e704e6ab291e375b1df516de8f688
|
data/.agignore
ADDED
@@ -3,33 +3,33 @@ module WorkerRoulette
|
|
3
3
|
attr_reader :sender, :namespace, :channel
|
4
4
|
|
5
5
|
LUA_ENQUEUE_WORK_ORDERS = <<-HERE
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
local counter_key = KEYS[1]
|
7
|
+
local job_board_key = KEYS[2]
|
8
|
+
local sender_key = KEYS[3]
|
9
|
+
local channel = KEYS[4]
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
11
|
+
local work_order = ARGV[1]
|
12
|
+
local job_notification = ARGV[2]
|
13
|
+
local redis_call = redis.call
|
14
|
+
local zscore = 'ZSCORE'
|
15
|
+
local incr = 'INCR'
|
16
|
+
local zadd = 'ZADD'
|
17
|
+
local rpush = 'RPUSH'
|
18
|
+
local publish = 'PUBLISH'
|
19
|
+
local zcard = 'ZCARD'
|
20
|
+
local del = 'DEL'
|
21
21
|
|
22
|
-
|
23
|
-
|
22
|
+
local function enqueue_work_orders(work_order, job_notification)
|
23
|
+
redis_call(rpush, sender_key, work_order)
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
end
|
25
|
+
-- called when a work from a new sender is added
|
26
|
+
if (redis_call(zscore, job_board_key, sender_key) == false) then
|
27
|
+
local count = redis_call(incr, counter_key)
|
28
|
+
redis_call(zadd, job_board_key, count, sender_key)
|
30
29
|
end
|
30
|
+
end
|
31
31
|
|
32
|
-
|
32
|
+
enqueue_work_orders(work_order, job_notification)
|
33
33
|
HERE
|
34
34
|
|
35
35
|
def initialize(redis_pool, sender, namespace = nil)
|
@@ -47,7 +47,7 @@ module WorkerRoulette
|
|
47
47
|
|
48
48
|
def enqueue_work_order_without_headers(work_order, &callback)
|
49
49
|
@lua.call(LUA_ENQUEUE_WORK_ORDERS, [counter_key, job_board_key, sender_key, @channel],
|
50
|
-
|
50
|
+
[WorkerRoulette.dump(work_order), WorkerRoulette::JOB_NOTIFICATIONS], &callback)
|
51
51
|
end
|
52
52
|
|
53
53
|
def job_board_key
|
@@ -68,4 +68,4 @@ module WorkerRoulette
|
|
68
68
|
Hash['sender' => sender]
|
69
69
|
end
|
70
70
|
end
|
71
|
-
end
|
71
|
+
end
|
data/lib/worker_roulette/lua.rb
CHANGED
@@ -8,7 +8,7 @@ module WorkerRoulette
|
|
8
8
|
|
9
9
|
def call(lua_script, keys_accessed = [], args = [], &callback)
|
10
10
|
@connection_pool.with do |redis|
|
11
|
-
|
11
|
+
evalsha(redis, lua_script, keys_accessed, args, &callback)
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
@@ -26,14 +26,14 @@ module WorkerRoulette
|
|
26
26
|
|
27
27
|
def eval(redis, lua_script, keys_accessed, args, &callback)
|
28
28
|
results = redis.eval(lua_script, keys_accessed.length, *keys_accessed, *args)
|
29
|
-
results.callback
|
29
|
+
results.callback(&callback) if callback
|
30
30
|
results.errback {|err_msg| raise EM::Hiredis::RedisError.new(err_msg)}
|
31
31
|
end
|
32
32
|
|
33
33
|
def evalsha(redis, lua_script, keys_accessed, args, &callback)
|
34
34
|
if redis.class == EM::Hiredis::Client
|
35
35
|
results = redis.evalsha(sha(lua_script), keys_accessed.length, *keys_accessed, *args)
|
36
|
-
results.callback
|
36
|
+
results.callback(&callback) if callback
|
37
37
|
results.errback {eval(redis, lua_script, keys_accessed, args, &callback)}
|
38
38
|
else
|
39
39
|
begin
|
@@ -47,4 +47,4 @@ module WorkerRoulette
|
|
47
47
|
results
|
48
48
|
end
|
49
49
|
end
|
50
|
-
end
|
50
|
+
end
|
@@ -1,71 +1,106 @@
|
|
1
|
-
require 'timers'
|
2
|
-
|
3
1
|
module WorkerRoulette
|
4
2
|
class Tradesman
|
5
3
|
attr_reader :last_sender, :remaining_jobs, :timer
|
6
4
|
|
7
5
|
LUA_DRAIN_WORK_ORDERS = <<-HERE
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
6
|
+
local empty_string = ""
|
7
|
+
local job_board_key = KEYS[1]
|
8
|
+
local last_sender_key = KEYS[2] or empty_string
|
9
|
+
local sender_key = ARGV[1] or empty_string
|
10
|
+
local redis_call = redis.call
|
11
|
+
local lock_key_prefix = "L*:"
|
12
|
+
local lock_value = 1
|
13
|
+
local ex = "EX"
|
14
|
+
local nx = "NX"
|
15
|
+
local get = "GET"
|
16
|
+
local set = "SET"
|
17
|
+
local del = "DEL"
|
18
|
+
local lrange = "LRANGE"
|
19
|
+
local zrank = "ZRANK"
|
20
|
+
local zrange = "ZRANGE"
|
21
|
+
local zrem = "ZREM"
|
22
|
+
local zcard = 'ZCARD'
|
23
|
+
|
24
|
+
local function drain_work_orders(job_board_key, last_sender_key, sender_key)
|
25
|
+
|
26
|
+
--kill lock for last_sender_key
|
27
|
+
if last_sender_key ~= empty_string then
|
28
|
+
local last_sender_lock_key = lock_key_prefix .. last_sender_key
|
29
|
+
redis_call(del, last_sender_lock_key)
|
30
|
+
end
|
31
|
+
|
32
|
+
if sender_key == empty_string then
|
33
|
+
sender_key = redis_call(zrange, job_board_key, 0, 0)[1] or empty_string
|
34
|
+
|
35
|
+
-- return if job_board is empty
|
36
|
+
if sender_key == empty_string then
|
37
|
+
return {empty_string, {}, 0}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
local lock_key = lock_key_prefix .. sender_key
|
42
|
+
local was_not_locked = redis_call(set, lock_key, lock_value, ex, 3, nx)
|
43
|
+
|
44
|
+
if was_not_locked then
|
45
|
+
local work_orders = redis_call(lrange, sender_key, 0, -1)
|
46
|
+
redis_call(del, sender_key)
|
33
47
|
|
34
|
-
|
35
|
-
|
48
|
+
redis_call(zrem, job_board_key, sender_key)
|
49
|
+
local remaining_jobs = redis_call(zcard, job_board_key) or 0
|
36
50
|
|
37
|
-
|
38
|
-
|
39
|
-
|
51
|
+
return {sender_key, work_orders, remaining_jobs}
|
52
|
+
else
|
53
|
+
local sender_index = redis_call(zrank, job_board_key, sender_key)
|
54
|
+
local next_index = sender_index + 1
|
55
|
+
local next_sender_key = redis_call(zrange, job_board_key, next_index, next_index)[1]
|
56
|
+
if next_sender_key then
|
57
|
+
return drain_work_orders(job_board_key, empty_string, next_sender_key)
|
58
|
+
else
|
59
|
+
-- return if job_board is empty
|
60
|
+
return {empty_string, {}, 0}
|
61
|
+
end
|
62
|
+
end
|
40
63
|
end
|
41
|
-
end
|
42
64
|
|
43
|
-
|
44
|
-
|
65
|
+
return drain_work_orders(job_board_key, last_sender_key, empty_string)
|
66
|
+
HERE
|
67
|
+
|
68
|
+
LUA_DRAIN_WORK_ORDERS_FOR_SENDER = <<-THERE
|
69
|
+
local empty_string = ""
|
70
|
+
local job_board_key = KEYS[1]
|
71
|
+
local sender_key = KEYS[2] or empty_string
|
72
|
+
local redis_call = redis.call
|
73
|
+
local lock_key_prefix = "L*:"
|
74
|
+
local lock_value = 1
|
75
|
+
local get = "GET"
|
76
|
+
local del = "DEL"
|
77
|
+
local lrange = "LRANGE"
|
78
|
+
local zrange = "ZRANGE"
|
79
|
+
local zrem = "ZREM"
|
80
|
+
|
81
|
+
local function drain_work_orders_for_sender(job_board_key, sender_key)
|
82
|
+
|
83
|
+
if sender_key == empty_string then
|
84
|
+
return {empty_string, {}, 0}
|
85
|
+
end
|
45
86
|
|
46
|
-
|
47
|
-
|
48
|
-
redis_call(del, sender_key)
|
87
|
+
local lock_key = lock_key_prefix .. sender_key
|
88
|
+
was_locked = redis_call(get, lock_key)
|
49
89
|
|
50
|
-
|
51
|
-
|
90
|
+
if was_locked == 1 then
|
91
|
+
local work_orders = redis_call(lrange, sender_key, 0, -1)
|
92
|
+
redis_call(del, sender_key)
|
52
93
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
return drain_work_orders(job_board_key, empty_string, next_sender_key)
|
60
|
-
else
|
61
|
-
-- return if job_board is empty
|
62
|
-
return {empty_string, {}, 0}
|
94
|
+
redis_call(zrem, job_board_key, sender_key)
|
95
|
+
|
96
|
+
return { sender_key, work_orders }
|
97
|
+
else
|
98
|
+
return { sender_key, {} }
|
99
|
+
end
|
63
100
|
end
|
64
|
-
end
|
65
|
-
end
|
66
101
|
|
67
|
-
|
68
|
-
|
102
|
+
return drain_work_orders_for_sender(job_board_key, sender_key)
|
103
|
+
THERE
|
69
104
|
|
70
105
|
def initialize(redis_pool, evented, namespace = nil, polling_time = WorkerRoulette::DEFAULT_POLLING_TIME)
|
71
106
|
@evented = evented
|
@@ -73,7 +108,6 @@ module WorkerRoulette
|
|
73
108
|
@redis_pool = redis_pool
|
74
109
|
@namespace = namespace
|
75
110
|
@channel = namespace || WorkerRoulette::JOB_NOTIFICATIONS
|
76
|
-
@timer = Timers::Group.new
|
77
111
|
@lua = Lua.new(@redis_pool)
|
78
112
|
@remaining_jobs = 0
|
79
113
|
end
|
@@ -102,16 +136,40 @@ module WorkerRoulette
|
|
102
136
|
end
|
103
137
|
end
|
104
138
|
|
139
|
+
def get_more_work_for_last_sender(&on_message_callback)
|
140
|
+
return unless on_message_callback
|
141
|
+
more_work_orders! do |work|
|
142
|
+
on_message_callback.call(work) if work.any?
|
143
|
+
if @evented
|
144
|
+
evented_drain_work_queue!(&on_message_callback)
|
145
|
+
else
|
146
|
+
non_evented_drain_work_queue!(&on_message_callback)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def more_work_orders!(&callback)
|
152
|
+
@lua.call(LUA_DRAIN_WORK_ORDERS_FOR_SENDER, [job_board_key, @last_sender]) do |results|
|
153
|
+
sender_key = results[0]
|
154
|
+
raise "wrong sender key returned from LUA_DRAIN_WORK_ORDERS_FOR_SENDER" unless sender_key == @last_sender
|
155
|
+
work_orders = results[1]
|
156
|
+
work = work_orders.map {|work_order| WorkerRoulette.load(work_order)}
|
157
|
+
callback.call work if callback
|
158
|
+
work
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
105
162
|
def job_board_key
|
106
163
|
@job_board_key ||= WorkerRoulette.job_board_key(@namespace)
|
107
164
|
end
|
108
165
|
|
109
|
-
|
166
|
+
private
|
167
|
+
|
110
168
|
def evented_drain_work_queue!(&on_message_callback)
|
111
169
|
if remaining_jobs > 0
|
112
170
|
EM.next_tick {wait_for_work_orders(&on_message_callback)}
|
113
171
|
else
|
114
|
-
EM.add_timer(@polling_time) {wait_for_work_orders(&on_message_callback)}
|
172
|
+
EM.add_timer(@polling_time) { wait_for_work_orders(&on_message_callback) }
|
115
173
|
end
|
116
174
|
end
|
117
175
|
|
@@ -119,7 +177,8 @@ module WorkerRoulette
|
|
119
177
|
if remaining_jobs > 0
|
120
178
|
wait_for_work_orders(&on_message_callback)
|
121
179
|
else
|
122
|
-
|
180
|
+
sleep 2
|
181
|
+
wait_for_work_orders(&on_message_callback)
|
123
182
|
end
|
124
183
|
end
|
125
184
|
end
|
@@ -99,6 +99,29 @@ module WorkerRoulette
|
|
99
99
|
end
|
100
100
|
end
|
101
101
|
|
102
|
+
it "should remove the lock from the last_sender's queue" do
|
103
|
+
most_recent_sender = 'most_recent_sender'
|
104
|
+
most_recent_foreman = worker_roulette.foreman(most_recent_sender)
|
105
|
+
other_foreman = worker_roulette.foreman('katie_80')
|
106
|
+
|
107
|
+
other_foreman.enqueue_work_order(work_orders) do
|
108
|
+
most_recent_foreman.enqueue_work_order(work_orders) do
|
109
|
+
expect(redis.keys("L*:*").length).to eq(0)
|
110
|
+
subject.work_orders! do
|
111
|
+
expect(redis.get("L*:katie_80")).to eq("1")
|
112
|
+
expect(redis.keys("L*:*").length).to eq(1)
|
113
|
+
subject.work_orders! do
|
114
|
+
expect(redis.keys("L*:*").length).to eq(1)
|
115
|
+
expect(redis.get("L*:most_recent_sender")).to eq("1")
|
116
|
+
subject.work_orders!
|
117
|
+
done(0.2) do
|
118
|
+
expect(redis.keys("L*:*").length).to eq(0)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
102
125
|
|
103
126
|
it "should drain one set of work_orders from the sender's slot in the job board" do
|
104
127
|
foreman.enqueue_work_order(work_orders) do
|
@@ -1,5 +1,9 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
module WorkerRoulette
|
3
|
+
class Tradesman
|
4
|
+
attr_reader :lua
|
5
|
+
end
|
6
|
+
|
3
7
|
describe WorkerRoulette do
|
4
8
|
let(:sender) {'katie_80'}
|
5
9
|
let(:work_orders) {["hello", "foreman"]}
|
@@ -12,6 +16,10 @@ module WorkerRoulette
|
|
12
16
|
|
13
17
|
let(:redis) {Redis.new(worker_roulette.redis_config)}
|
14
18
|
|
19
|
+
before do
|
20
|
+
redis.flushall
|
21
|
+
end
|
22
|
+
|
15
23
|
it "should exist" do
|
16
24
|
expect(worker_roulette).to be_instance_of(WorkerRoulette)
|
17
25
|
end
|
@@ -65,35 +73,52 @@ module WorkerRoulette
|
|
65
73
|
end
|
66
74
|
|
67
75
|
context Tradesman do
|
68
|
-
let(:foreman)
|
69
|
-
|
76
|
+
let(:foreman) { worker_roulette.foreman(sender) }
|
77
|
+
subject(:tradesman) { worker_roulette.tradesman }
|
70
78
|
|
71
79
|
before do
|
72
80
|
foreman.enqueue_work_order(work_orders)
|
73
81
|
end
|
74
82
|
|
83
|
+
context 'removing locks from queues' do
|
84
|
+
it "for the last_sender's queue" do
|
85
|
+
most_recent_sender = 'most_recent_sender'
|
86
|
+
most_recent_foreman = worker_roulette.foreman(most_recent_sender)
|
87
|
+
most_recent_foreman.enqueue_work_order(work_orders)
|
88
|
+
expect(redis.keys("L*:*").length).to eq(0)
|
89
|
+
tradesman.work_orders!
|
90
|
+
expect(redis.get("L*:katie_80")).to eq("1")
|
91
|
+
expect(redis.keys("L*:*").length).to eq(1)
|
92
|
+
tradesman.work_orders!
|
93
|
+
expect(redis.keys("L*:*").length).to eq(1)
|
94
|
+
expect(redis.get("L*:most_recent_sender")).to eq("1")
|
95
|
+
tradesman.work_orders!
|
96
|
+
expect(redis.keys("L*:*").length).to eq(0)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
75
100
|
it "should have a last sender if it found messages" do
|
76
|
-
expect(
|
77
|
-
expect(
|
101
|
+
expect(tradesman.work_orders!.length).to eq(1)
|
102
|
+
expect(tradesman.last_sender).to eq(sender)
|
78
103
|
end
|
79
104
|
|
80
105
|
it "should not have a last sender if it found no messages" do
|
81
|
-
expect(
|
82
|
-
expect(
|
83
|
-
expect(
|
106
|
+
expect(tradesman.work_orders!.length).to eq(1)
|
107
|
+
expect(tradesman.work_orders!.length).to eq(0)
|
108
|
+
expect(tradesman.last_sender).to be_nil
|
84
109
|
end
|
85
110
|
|
86
111
|
it "should drain one set of work_orders from the sender's work queue" do
|
87
|
-
expect(
|
88
|
-
expect(
|
89
|
-
expect(
|
112
|
+
expect(tradesman.work_orders!).to eq([work_orders_with_headers])
|
113
|
+
expect(tradesman.work_orders!).to be_empty
|
114
|
+
expect(tradesman.work_orders!).to be_empty #does not throw an error if queue is already empty
|
90
115
|
end
|
91
116
|
|
92
117
|
it "should drain all the work_orders from the sender's work queue" do
|
93
118
|
foreman.enqueue_work_order(work_orders)
|
94
|
-
expect(
|
95
|
-
expect(
|
96
|
-
expect(
|
119
|
+
expect(tradesman.work_orders!).to eq([work_orders_with_headers, work_orders_with_headers])
|
120
|
+
expect(tradesman.work_orders!).to be_empty
|
121
|
+
expect(tradesman.work_orders!).to be_empty #does not throw an error if queue is already empty
|
97
122
|
end
|
98
123
|
|
99
124
|
it "should take the oldest sender off the job board (FIFO)" do
|
@@ -101,21 +126,16 @@ module WorkerRoulette
|
|
101
126
|
most_recent_sender = 'most_recent_sender'
|
102
127
|
most_recent_foreman = worker_roulette.foreman(most_recent_sender)
|
103
128
|
most_recent_foreman.enqueue_work_order(work_orders)
|
104
|
-
expect(redis.zrange(
|
105
|
-
|
106
|
-
expect(redis.zrange(
|
129
|
+
expect(redis.zrange(tradesman.job_board_key, 0, -1)).to eq([oldest_sender, most_recent_sender])
|
130
|
+
tradesman.work_orders!
|
131
|
+
expect(redis.zrange(tradesman.job_board_key, 0, -1)).to eq([most_recent_sender])
|
107
132
|
end
|
108
133
|
|
109
134
|
it "should get the work_orders from the next queue when a new job is ready, then poll for new work" do
|
110
|
-
|
111
|
-
expect(subject).to receive(:work_orders!).and_call_original
|
112
|
-
expect(subject.timer).to receive(:after)
|
113
|
-
|
114
|
-
foreman.enqueue_work_order(work_orders)
|
115
|
-
|
116
|
-
subject.wait_for_work_orders do |redis_work_orders|
|
135
|
+
tradesman.wait_for_work_orders do |redis_work_orders|
|
117
136
|
expect(redis_work_orders).to eq([work_orders_with_headers])
|
118
|
-
expect(
|
137
|
+
expect(tradesman.last_sender).to eq('katie_80')
|
138
|
+
allow(tradesman).to receive(:wait_for_work_orders)
|
119
139
|
end
|
120
140
|
end
|
121
141
|
|
@@ -133,7 +153,28 @@ module WorkerRoulette
|
|
133
153
|
expect(work.to_s).to match("some old fashion work")
|
134
154
|
expect(work.to_s).not_to match("evil")
|
135
155
|
expect(tradesman.last_sender).to eq('foreman')
|
156
|
+
allow(tradesman).to receive(:wait_for_work_orders)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
it "goes back to the channel to get more work for the same sender" do
|
161
|
+
tradesman.wait_for_work_orders do |redis_work_orders|
|
162
|
+
expect(redis_work_orders).to eq([work_orders_with_headers])
|
163
|
+
expect(tradesman.last_sender).to eq('katie_80')
|
164
|
+
allow(tradesman).to receive(:wait_for_work_orders)
|
136
165
|
end
|
166
|
+
|
167
|
+
expect(tradesman.lua).to receive(:call).with(Tradesman::LUA_DRAIN_WORK_ORDERS_FOR_SENDER, [instance_of(String), sender])
|
168
|
+
tradesman.get_more_work_for_last_sender do |redis_work_orders|
|
169
|
+
expect(redis_work_orders).to eq([])
|
170
|
+
end
|
171
|
+
|
172
|
+
foreman.enqueue_work_order("more_work_orders")
|
173
|
+
expect(tradesman.lua).to receive(:call).with(Tradesman::LUA_DRAIN_WORK_ORDERS_FOR_SENDER, [instance_of(String), sender])
|
174
|
+
tradesman.get_more_work_for_last_sender do |redis_work_orders|
|
175
|
+
expect(redis_work_orders).to eq(["more_work_orders"])
|
176
|
+
end
|
177
|
+
|
137
178
|
end
|
138
179
|
|
139
180
|
context "Failure" do
|
@@ -149,15 +190,6 @@ module WorkerRoulette
|
|
149
190
|
expect(pooled_redis.info["connected_clients"].to_i).to be > (worker_roulette.pool_size)
|
150
191
|
end
|
151
192
|
end
|
152
|
-
|
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
|
160
|
-
end
|
161
193
|
end
|
162
194
|
end
|
163
195
|
end
|
data/worker_roulette.gemspec
CHANGED
@@ -10,28 +10,25 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.email = ['classicist@gmail.com']
|
11
11
|
spec.description = %q{Pub Sub Queue for Redis that ensures ordered processing}
|
12
12
|
spec.summary = %q{Pub Sub Queue for Redis that ensures ordered processing}
|
13
|
-
spec.homepage = 'https://github.com/
|
13
|
+
spec.homepage = 'https://github.com/classicist/worker_roulette'
|
14
14
|
|
15
15
|
spec.files = `git ls-files`.split($/)
|
16
16
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
17
|
spec.test_files = spec.files.grep(%r{^(spec)/})
|
18
18
|
spec.require_paths = ['lib']
|
19
19
|
|
20
|
-
spec.add_dependency 'oj'
|
21
|
-
spec.add_dependency 'redis', '~> 3.
|
22
|
-
spec.add_dependency 'hiredis', '~> 0.
|
23
|
-
spec.add_dependency 'em-hiredis', '~> 0.
|
24
|
-
spec.add_dependency 'connection_pool'
|
25
|
-
spec.add_dependency 'eventmachine', '~> 1.0
|
26
|
-
spec.add_dependency 'timers', '~> 3.0.1'
|
20
|
+
spec.add_dependency 'oj', '~> 2.10'
|
21
|
+
spec.add_dependency 'redis', '~> 3.1'
|
22
|
+
spec.add_dependency 'hiredis', '~> 0.5'
|
23
|
+
spec.add_dependency 'em-hiredis', '~> 0.3'
|
24
|
+
spec.add_dependency 'connection_pool', '~> 2.0'
|
25
|
+
spec.add_dependency 'eventmachine', '~> 1.0'
|
27
26
|
|
28
|
-
spec.add_development_dependency 'bundler'
|
29
|
-
spec.add_development_dependency 'rake'
|
30
|
-
spec.add_development_dependency 'rspec', '~> 3.
|
31
|
-
spec.add_development_dependency 'pry-
|
32
|
-
spec.add_development_dependency 'simplecov'
|
33
|
-
spec.add_development_dependency 'simplecov-rcov'
|
34
|
-
spec.add_development_dependency 'rspec_junit_formatter'
|
35
|
-
spec.add_development_dependency 'guard'
|
36
|
-
spec.add_development_dependency 'guard-rspec'
|
27
|
+
spec.add_development_dependency 'bundler', '~> 1.7'
|
28
|
+
spec.add_development_dependency 'rake', '~> 10.3'
|
29
|
+
spec.add_development_dependency 'rspec', '~> 3.1'
|
30
|
+
spec.add_development_dependency 'pry-byebug', '~> 2.0'
|
31
|
+
spec.add_development_dependency 'simplecov', '~> 0.9'
|
32
|
+
spec.add_development_dependency 'simplecov-rcov', '~> 0.2'
|
33
|
+
spec.add_development_dependency 'rspec_junit_formatter', '~> 0.2'
|
37
34
|
end
|
metadata
CHANGED
@@ -1,239 +1,197 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: worker_roulette
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.12
|
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-
|
11
|
+
date: 2014-11-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: oj
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '2.10'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '2.10'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: redis
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - ~>
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 3.
|
33
|
+
version: '3.1'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - ~>
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 3.
|
40
|
+
version: '3.1'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: hiredis
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - ~>
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 0.
|
47
|
+
version: '0.5'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - ~>
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 0.
|
54
|
+
version: '0.5'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: em-hiredis
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - ~>
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 0.
|
61
|
+
version: '0.3'
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - ~>
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: 0.
|
68
|
+
version: '0.3'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: connection_pool
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
75
|
+
version: '2.0'
|
76
76
|
type: :runtime
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
82
|
+
version: '2.0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: eventmachine
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - ~>
|
87
|
+
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: 1.0
|
89
|
+
version: '1.0'
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- - ~>
|
94
|
+
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: 1.0
|
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
|
96
|
+
version: '1.0'
|
111
97
|
- !ruby/object:Gem::Dependency
|
112
98
|
name: bundler
|
113
99
|
requirement: !ruby/object:Gem::Requirement
|
114
100
|
requirements:
|
115
|
-
- -
|
101
|
+
- - "~>"
|
116
102
|
- !ruby/object:Gem::Version
|
117
|
-
version: '
|
103
|
+
version: '1.7'
|
118
104
|
type: :development
|
119
105
|
prerelease: false
|
120
106
|
version_requirements: !ruby/object:Gem::Requirement
|
121
107
|
requirements:
|
122
|
-
- -
|
108
|
+
- - "~>"
|
123
109
|
- !ruby/object:Gem::Version
|
124
|
-
version: '
|
110
|
+
version: '1.7'
|
125
111
|
- !ruby/object:Gem::Dependency
|
126
112
|
name: rake
|
127
113
|
requirement: !ruby/object:Gem::Requirement
|
128
114
|
requirements:
|
129
|
-
- -
|
115
|
+
- - "~>"
|
130
116
|
- !ruby/object:Gem::Version
|
131
|
-
version: '
|
117
|
+
version: '10.3'
|
132
118
|
type: :development
|
133
119
|
prerelease: false
|
134
120
|
version_requirements: !ruby/object:Gem::Requirement
|
135
121
|
requirements:
|
136
|
-
- -
|
122
|
+
- - "~>"
|
137
123
|
- !ruby/object:Gem::Version
|
138
|
-
version: '
|
124
|
+
version: '10.3'
|
139
125
|
- !ruby/object:Gem::Dependency
|
140
126
|
name: rspec
|
141
127
|
requirement: !ruby/object:Gem::Requirement
|
142
128
|
requirements:
|
143
|
-
- - ~>
|
129
|
+
- - "~>"
|
144
130
|
- !ruby/object:Gem::Version
|
145
|
-
version: 3.
|
131
|
+
version: '3.1'
|
146
132
|
type: :development
|
147
133
|
prerelease: false
|
148
134
|
version_requirements: !ruby/object:Gem::Requirement
|
149
135
|
requirements:
|
150
|
-
- - ~>
|
136
|
+
- - "~>"
|
151
137
|
- !ruby/object:Gem::Version
|
152
|
-
version: 3.
|
138
|
+
version: '3.1'
|
153
139
|
- !ruby/object:Gem::Dependency
|
154
|
-
name: pry-
|
140
|
+
name: pry-byebug
|
155
141
|
requirement: !ruby/object:Gem::Requirement
|
156
142
|
requirements:
|
157
|
-
- -
|
143
|
+
- - "~>"
|
158
144
|
- !ruby/object:Gem::Version
|
159
|
-
version: '0'
|
145
|
+
version: '2.0'
|
160
146
|
type: :development
|
161
147
|
prerelease: false
|
162
148
|
version_requirements: !ruby/object:Gem::Requirement
|
163
149
|
requirements:
|
164
|
-
- -
|
150
|
+
- - "~>"
|
165
151
|
- !ruby/object:Gem::Version
|
166
|
-
version: '0'
|
152
|
+
version: '2.0'
|
167
153
|
- !ruby/object:Gem::Dependency
|
168
154
|
name: simplecov
|
169
155
|
requirement: !ruby/object:Gem::Requirement
|
170
156
|
requirements:
|
171
|
-
- -
|
157
|
+
- - "~>"
|
172
158
|
- !ruby/object:Gem::Version
|
173
|
-
version: '0'
|
159
|
+
version: '0.9'
|
174
160
|
type: :development
|
175
161
|
prerelease: false
|
176
162
|
version_requirements: !ruby/object:Gem::Requirement
|
177
163
|
requirements:
|
178
|
-
- -
|
164
|
+
- - "~>"
|
179
165
|
- !ruby/object:Gem::Version
|
180
|
-
version: '0'
|
166
|
+
version: '0.9'
|
181
167
|
- !ruby/object:Gem::Dependency
|
182
168
|
name: simplecov-rcov
|
183
169
|
requirement: !ruby/object:Gem::Requirement
|
184
170
|
requirements:
|
185
|
-
- -
|
171
|
+
- - "~>"
|
186
172
|
- !ruby/object:Gem::Version
|
187
|
-
version: '0'
|
173
|
+
version: '0.2'
|
188
174
|
type: :development
|
189
175
|
prerelease: false
|
190
176
|
version_requirements: !ruby/object:Gem::Requirement
|
191
177
|
requirements:
|
192
|
-
- -
|
178
|
+
- - "~>"
|
193
179
|
- !ruby/object:Gem::Version
|
194
|
-
version: '0'
|
180
|
+
version: '0.2'
|
195
181
|
- !ruby/object:Gem::Dependency
|
196
182
|
name: rspec_junit_formatter
|
197
183
|
requirement: !ruby/object:Gem::Requirement
|
198
184
|
requirements:
|
199
|
-
- -
|
200
|
-
- !ruby/object:Gem::Version
|
201
|
-
version: '0'
|
202
|
-
type: :development
|
203
|
-
prerelease: false
|
204
|
-
version_requirements: !ruby/object:Gem::Requirement
|
205
|
-
requirements:
|
206
|
-
- - ! '>='
|
207
|
-
- !ruby/object:Gem::Version
|
208
|
-
version: '0'
|
209
|
-
- !ruby/object:Gem::Dependency
|
210
|
-
name: guard
|
211
|
-
requirement: !ruby/object:Gem::Requirement
|
212
|
-
requirements:
|
213
|
-
- - ! '>='
|
214
|
-
- !ruby/object:Gem::Version
|
215
|
-
version: '0'
|
216
|
-
type: :development
|
217
|
-
prerelease: false
|
218
|
-
version_requirements: !ruby/object:Gem::Requirement
|
219
|
-
requirements:
|
220
|
-
- - ! '>='
|
221
|
-
- !ruby/object:Gem::Version
|
222
|
-
version: '0'
|
223
|
-
- !ruby/object:Gem::Dependency
|
224
|
-
name: guard-rspec
|
225
|
-
requirement: !ruby/object:Gem::Requirement
|
226
|
-
requirements:
|
227
|
-
- - ! '>='
|
185
|
+
- - "~>"
|
228
186
|
- !ruby/object:Gem::Version
|
229
|
-
version: '0'
|
187
|
+
version: '0.2'
|
230
188
|
type: :development
|
231
189
|
prerelease: false
|
232
190
|
version_requirements: !ruby/object:Gem::Requirement
|
233
191
|
requirements:
|
234
|
-
- -
|
192
|
+
- - "~>"
|
235
193
|
- !ruby/object:Gem::Version
|
236
|
-
version: '0'
|
194
|
+
version: '0.2'
|
237
195
|
description: Pub Sub Queue for Redis that ensures ordered processing
|
238
196
|
email:
|
239
197
|
- classicist@gmail.com
|
@@ -241,9 +199,10 @@ executables: []
|
|
241
199
|
extensions: []
|
242
200
|
extra_rdoc_files: []
|
243
201
|
files:
|
244
|
-
- .
|
245
|
-
- .
|
246
|
-
- .
|
202
|
+
- ".agignore"
|
203
|
+
- ".gitignore"
|
204
|
+
- ".rspec"
|
205
|
+
- ".simplecov"
|
247
206
|
- Gemfile
|
248
207
|
- Guardfile
|
249
208
|
- LICENSE.txt
|
@@ -264,7 +223,7 @@ files:
|
|
264
223
|
- spec/unit/lua_spec.rb
|
265
224
|
- spec/unit/readlock_spec.rb
|
266
225
|
- worker_roulette.gemspec
|
267
|
-
homepage: https://github.com/
|
226
|
+
homepage: https://github.com/classicist/worker_roulette
|
268
227
|
licenses: []
|
269
228
|
metadata: {}
|
270
229
|
post_install_message:
|
@@ -273,17 +232,17 @@ require_paths:
|
|
273
232
|
- lib
|
274
233
|
required_ruby_version: !ruby/object:Gem::Requirement
|
275
234
|
requirements:
|
276
|
-
- -
|
235
|
+
- - ">="
|
277
236
|
- !ruby/object:Gem::Version
|
278
237
|
version: '0'
|
279
238
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
280
239
|
requirements:
|
281
|
-
- -
|
240
|
+
- - ">="
|
282
241
|
- !ruby/object:Gem::Version
|
283
242
|
version: '0'
|
284
243
|
requirements: []
|
285
244
|
rubyforge_project:
|
286
|
-
rubygems_version: 2.
|
245
|
+
rubygems_version: 2.4.3
|
287
246
|
signing_key:
|
288
247
|
specification_version: 4
|
289
248
|
summary: Pub Sub Queue for Redis that ensures ordered processing
|