worker_roulette 0.1.0 → 0.1.1

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.
data/README.md CHANGED
@@ -121,12 +121,12 @@ end
121
121
  ## Performance
122
122
  Running the performance tests on my laptop, the numbers break down like this:
123
123
  ### Async Api
124
- - Manual: ~4200 read-write round-trips / second
125
- - Pubsub: ~5200 read-write round-trips / second
124
+ - Pubsub: ~5500 read-write round-trips / second
125
+ - Manual: ~4500 read-write round-trips / second
126
126
 
127
127
  ### Sync Api
128
- - Manual: ~1600 read-write round-trips / second
129
- - Pubsub: ~2000 read-write round-trips / second
128
+ - Pubsub: ~2700 read-write round-trips / second
129
+ - Manual: ~2500 read-write round-trips / second
130
130
 
131
131
  To run the perf tests yourself run `bundle exec spec:perf`
132
132
 
@@ -33,8 +33,7 @@ module WorkerRoulette
33
33
  end
34
34
 
35
35
  def self.a_foreman(sender, channel = nil)
36
- raise "WorkerRoulette not Started" unless @foreman_connection_pool
37
- AForeman.new(sender, @foreman_connection_pool, channel)
36
+ foreman(sender, channel)
38
37
  end
39
38
 
40
39
  def self.a_tradesman(channel = nil)
@@ -58,6 +57,29 @@ module WorkerRoulette
58
57
  @redis_config.dup
59
58
  end
60
59
 
60
+ def self.dump(obj)
61
+ Oj.dump(obj)
62
+ rescue Oj::ParseError => e
63
+ {'error' => e, 'unparsable_string' => obj}
64
+ end
65
+
66
+ def self.load(json)
67
+ Oj.load(json)
68
+ rescue Oj::ParseError => e
69
+ {'error' => e, 'unparsable_string' => obj}
70
+ end
71
+
72
+ def self.job_board_key(namespace = nil)
73
+ "#{namespace + ':' if namespace}#{WorkerRoulette::JOB_BOARD}"
74
+ end
75
+
76
+ def self.sender_key(sender, namespace = nil)
77
+ "#{namespace + ':' if namespace}#{sender}"
78
+ end
79
+
80
+ def self.counter_key(sender, namespace = nil)
81
+ "#{namespace + ':' if namespace}counter_key"
82
+ end
61
83
  private
62
84
  def self.new_redis
63
85
  if @evented
@@ -8,13 +8,6 @@ module WorkerRoulette
8
8
  @redis_pubsub.subscribe(@channel)
9
9
  end
10
10
 
11
- def work_orders!(&callback)
12
- Lua.call(self.class.lua_drain_work_orders, [job_board_key, nil], [@namespace]) do |results|
13
- @sender = (results.first || '').split(':').first
14
- callback.call (results[1] || []).map {|work_order| Oj.load(work_order)} if callback
15
- end
16
- end
17
-
18
11
  def unsubscribe(&callback)
19
12
  deferable = @redis_pubsub.unsubscribe(@channel)
20
13
  deferable.callback do
@@ -38,30 +31,5 @@ module WorkerRoulette
38
31
  work_orders! {|work_orders| on_message_callback.call(work_orders, nil, nil)}
39
32
  end
40
33
  end
41
-
42
- def self.lua_drain_work_orders
43
- <<-HERE
44
- local job_board_key = KEYS[1]
45
- local empty = KEYS[2]
46
- local namespace = ARGV[1]
47
-
48
- local function drain_work_orders(job_board_key, namespace)
49
- local sender_key = redis.call('ZRANGE', job_board_key, 0, 0)[1]
50
-
51
- if sender_key == false then
52
- return {}
53
- end
54
-
55
- local results = {}
56
- results[1] = sender_key
57
- results[2] = redis.call('LRANGE', sender_key, 0, -1)
58
- results[3] = redis.call('DEL', sender_key)
59
- results[4] = redis.call('ZREM', job_board_key, sender_key)
60
- return results
61
- end
62
-
63
- return drain_work_orders(job_board_key, namespace)
64
- HERE
65
- end
66
34
  end
67
35
  end
@@ -1,7 +1,6 @@
1
1
  module WorkerRoulette
2
2
  class Foreman
3
3
  attr_reader :sender
4
- COUNTER_KEY = 'counter_key'
5
4
 
6
5
  def initialize(sender, redis_pool, namespace = nil)
7
6
  @sender = sender
@@ -10,41 +9,60 @@ module WorkerRoulette
10
9
  @channel = namespace || WorkerRoulette::JOB_NOTIFICATIONS
11
10
  end
12
11
 
13
- def job_board_key
14
- @job_board_key ||= "#{@namespace + ':' if @namespace}#{WorkerRoulette::JOB_BOARD}"
12
+ def enqueue_work_order(work_order, headers = {}, &callback)
13
+ work_order = {'headers' => default_headers.merge(headers), 'payload' => work_order}
14
+ enqueue_work_order_without_headers(work_order, &callback)
15
15
  end
16
16
 
17
- def sender_key
18
- @sender_key = "#{@namespace + ':' if @namespace}#{@sender}"
17
+ def enqueue_work_order_without_headers(work_order, &callback)
18
+ Lua.call(self.class.lua_enqueue_work_orders, [counter_key, job_board_key, sender_key, @channel],
19
+ [WorkerRoulette.dump(work_order), WorkerRoulette::JOB_NOTIFICATIONS], &callback)
19
20
  end
20
21
 
21
- def counter_key
22
- @counter_key = "#{@namespace + ':' if @namespace}#{COUNTER_KEY}"
22
+ def job_board_key
23
+ @job_board_key ||= WorkerRoulette.job_board_key(@namespace)
23
24
  end
24
25
 
25
- def enqueue_work_order_without_headers(work_order, &callback)
26
- #Caveat Emptor: There is a race condition here, but it not serious;
27
- #the count may be incremented again by another process before the sender
28
- #is added to the job_queue. This is not a big deal bc it just means that
29
- #the sender's queue will be processed one slot behind it's rightful place.
30
- #This does not effect work_order ordering.
31
- @redis_pool.with({}) do |redis|
32
- @count = redis.incr(COUNTER_KEY)
33
- redis.multi do
34
- redis.zadd(job_board_key, @count, @sender)
35
- redis.rpush(sender_key, Oj.dump(work_order))
36
- redis.publish(@channel, WorkerRoulette::JOB_NOTIFICATIONS)
37
- end
38
- end
26
+ def counter_key
27
+ @counter_key ||= WorkerRoulette.counter_key(@namespace)
39
28
  end
40
29
 
41
- def enqueue_work_order(work_order, headers = {}, &callback)
42
- work_order = {'headers' => default_headers.merge(headers), 'payload' => work_order}
43
- enqueue_work_order_without_headers(work_order, &callback)
30
+ private
31
+ def sender_key
32
+ @sender_key = WorkerRoulette.sender_key(sender, @namespace)
44
33
  end
45
34
 
46
35
  def default_headers
47
36
  Hash['sender' => sender]
48
37
  end
38
+
39
+ def self.lua_enqueue_work_orders
40
+ <<-HERE
41
+ local counter_key = KEYS[1]
42
+ local job_board_key = KEYS[2]
43
+ local sender_key = KEYS[3]
44
+ local channel = KEYS[4]
45
+
46
+ local work_order = ARGV[1]
47
+ local job_notification = ARGV[2]
48
+
49
+ local function enqueue_work_orders(work_order, job_notification)
50
+ local result = sender_key .. ' updated'
51
+ local sender_on_job_board = redis.call('ZSCORE', job_board_key, sender_key)
52
+
53
+ if (sender_on_job_board == false) then
54
+ local count = redis.call('INCR', counter_key)
55
+ local job_added = redis.call('ZADD',job_board_key, count, sender_key)
56
+ result = sender_key .. ' added'
57
+ end
58
+
59
+ local work_added = redis.call('RPUSH',sender_key, work_order)
60
+ local job_board_update = redis.call('PUBLISH', channel, job_notification)
61
+ return result
62
+ end
63
+
64
+ return enqueue_work_orders(work_order, job_notification)
65
+ HERE
66
+ end
49
67
  end
50
68
  end
@@ -4,9 +4,7 @@ module WorkerRoulette
4
4
 
5
5
  def self.call(lua_script, keys_accessed = [], args = [], &callback)
6
6
  WorkerRoulette.tradesman_connection_pool.with do |redis|
7
- results = redis.evalsha(sha(lua_script), keys_accessed.length, *keys_accessed, *args)
8
- results.callback &callback
9
- results.errback {self.eval(redis, lua_script, keys_accessed, args, &callback)}
7
+ results = evalsha(redis, lua_script, keys_accessed, args, &callback)
10
8
  end
11
9
  end
12
10
 
@@ -24,8 +22,25 @@ module WorkerRoulette
24
22
 
25
23
  def self.eval(redis, lua_script, keys_accessed, args, &callback)
26
24
  results = redis.eval(lua_script, keys_accessed.size, *keys_accessed, *args)
27
- results.callback &callback
25
+ results.callback &callback if callback
28
26
  results.errback {|err_msg| raise EM::Hiredis::RedisError.new(err_msg)}
29
27
  end
28
+
29
+ def self.evalsha(redis, lua_script, keys_accessed, args, &callback)
30
+ if redis.class == EM::Hiredis::Client
31
+ results = redis.evalsha(sha(lua_script), keys_accessed.length, *keys_accessed, *args)
32
+ results.callback &callback if callback
33
+ results.errback {self.eval(redis, lua_script, keys_accessed, args, &callback)}
34
+ else
35
+ begin
36
+ results = redis.evalsha(sha(lua_script), keys_accessed, args)
37
+ rescue Redis::CommandError
38
+ results = redis.eval(lua_script, keys_accessed, args)
39
+ ensure
40
+ return callback.call results if callback
41
+ end
42
+ end
43
+ results
44
+ end
30
45
  end
31
46
  end
@@ -8,14 +8,6 @@ module WorkerRoulette
8
8
  @channel = namespace || WorkerRoulette::JOB_NOTIFICATIONS
9
9
  end
10
10
 
11
- def job_board_key
12
- @job_board_key ||= "#{@namespace + ':' if @namespace}#{WorkerRoulette::JOB_BOARD}"
13
- end
14
-
15
- def sender_key
16
- @sender_key = "#{@namespace + ':' if @namespace}#{@sender}"
17
- end
18
-
19
11
  def wait_for_work_orders(on_subscribe_callback = nil, &block)
20
12
  @pubsub_pool.with do |redis|
21
13
  redis.subscribe(@channel) do |on|
@@ -25,15 +17,12 @@ module WorkerRoulette
25
17
  end
26
18
  end
27
19
 
28
- def work_orders!
29
- @client_pool.with do |redis|
30
- get_sender_for_next_job(redis)
31
- results = redis.multi do
32
- redis.lrange(sender_key, 0, -1)
33
- redis.del(sender_key)
34
- redis.zrem(job_board_key, sender_key)
35
- end
36
- ((results || []).first || []).map {|work_order| Oj.load(work_order)}
20
+ def work_orders!(&callback)
21
+ Lua.call(self.class.lua_drain_work_orders, [job_board_key, nil], [@namespace]) do |results|
22
+ @sender = (results.first || '').split(':').first
23
+ work = (results[1] || []).map {|work_order| WorkerRoulette.load(work_order)}
24
+ callback.call work if callback
25
+ work
37
26
  end
38
27
  end
39
28
 
@@ -41,7 +30,40 @@ module WorkerRoulette
41
30
  @pubsub_pool.with {|redis| redis.unsubscribe(@channel)}
42
31
  end
43
32
 
33
+ def job_board_key
34
+ @job_board_key ||= WorkerRoulette.job_board_key(@namespace)
35
+ end
36
+
44
37
  private
38
+ def sender_key
39
+ @sender_key = WorkerRoulette.sender_key(@sender, @namespace)
40
+ end
41
+
42
+ def self.lua_drain_work_orders
43
+ <<-HERE
44
+ local job_board_key = KEYS[1]
45
+ local empty = KEYS[2]
46
+ local namespace = ARGV[1]
47
+
48
+ local function drain_work_orders(job_board_key, namespace)
49
+ local sender_key = redis.call('ZRANGE', job_board_key, 0, 0)[1]
50
+
51
+ if sender_key == false then
52
+ return {}
53
+ end
54
+
55
+ local results = {}
56
+ results[1] = sender_key
57
+ results[2] = redis.call('LRANGE', sender_key, 0, -1)
58
+ results[3] = redis.call('DEL', sender_key)
59
+ results[4] = redis.call('ZREM', job_board_key, sender_key)
60
+ return results
61
+ end
62
+
63
+ return drain_work_orders(job_board_key, namespace)
64
+ HERE
65
+ end
66
+
45
67
  def get_sender_for_next_job(redis)
46
68
  @sender = (redis.zrange(job_board_key, 0, 0) || []).first.to_s
47
69
  end
@@ -1,3 +1,3 @@
1
1
  module WorkerRoulette
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -12,7 +12,7 @@ WorkerRoulette.tradesman_connection_pool.with {|r| r.flushdb}
12
12
  puts "Redis Connection Pool Size: #{REDIS_CONNECTION_POOL_SIZE}"
13
13
 
14
14
  Benchmark.bmbm do |x|
15
- x.report "Time to insert and read #{ITERATIONS} large work_orders" do # ~1600 work_orders / second round trip; 50-50 read-write time; CPU and IO bound
15
+ x.report "Time to insert and read #{ITERATIONS} large work_orders" do # ~2500 work_orders / second round trip; 50-50 read-write time; CPU and IO bound
16
16
  WorkerRoulette.start(size: REDIS_CONNECTION_POOL_SIZE, evented: false)
17
17
  ITERATIONS.times do |iteration|
18
18
  sender = 'sender_' + iteration.to_s
@@ -33,7 +33,7 @@ EM::Hiredis.reconnect_timeout = 0.01
33
33
  WorkerRoulette.tradesman_connection_pool.with {|r| r.flushdb}
34
34
 
35
35
  Benchmark.bmbm do |x|
36
- x.report "Time for tradesmans to enqueue_work_order and read #{ITERATIONS} large work_orders via pubsub" do # ~2000 work_orders / second round trip
36
+ x.report "Time for tradesmans to enqueue_work_order and read #{ITERATIONS} large work_orders via pubsub" do # ~2700 work_orders / second round trip
37
37
  WorkerRoulette.start(size: REDIS_CONNECTION_POOL_SIZE, evented: false)
38
38
  ITERATIONS.times do |iteration|
39
39
  p = -> do
@@ -9,7 +9,7 @@ describe WorkerRoulette do
9
9
  let(:hello_work_order) {Hash['payload' => "hello"]}
10
10
  let(:foreman_work_order) {Hash['payload' => "foreman"]}
11
11
  let(:work_orders_with_headers) {default_headers.merge({'payload' => work_orders})}
12
- let(:jsonized_work_orders_with_headers) {[Oj.dump(work_orders_with_headers)]}
12
+ let(:jsonized_work_orders_with_headers) {[WorkerRoulette.dump(work_orders_with_headers)]}
13
13
 
14
14
  let(:redis) {Redis.new(WorkerRoulette.redis_config)}
15
15
 
@@ -17,7 +17,7 @@ describe WorkerRoulette do
17
17
  WorkerRoulette.start(evented: true)
18
18
  end
19
19
 
20
- context Foreman do
20
+ context "Evented Foreman" do
21
21
  let(:subject) {WorkerRoulette.a_foreman(sender)}
22
22
 
23
23
  it "should enqueue work" do
@@ -33,7 +33,7 @@ describe WorkerRoulette do
33
33
  it "should enqueue_work_order two work_orders in the sender's slot in the job board" do
34
34
  subject.enqueue_work_order(work_orders.first) do
35
35
  subject.enqueue_work_order(work_orders.last) do
36
- redis.lrange(sender, 0, -1).should == work_orders.map {|m| Oj.dump(default_headers.merge({'payload' => m})) }
36
+ redis.lrange(sender, 0, -1).should == work_orders.map {|m| WorkerRoulette.dump(default_headers.merge({'payload' => m})) }
37
37
  done
38
38
  end
39
39
  end
@@ -41,7 +41,7 @@ describe WorkerRoulette do
41
41
 
42
42
  it "should enqueue_work_order an array of work_orders without headers in the sender's slot in the job board" do
43
43
  subject.enqueue_work_order_without_headers(work_orders) do
44
- redis.lrange(sender, 0, -1).should == [Oj.dump(work_orders)]
44
+ redis.lrange(sender, 0, -1).should == [WorkerRoulette.dump(work_orders)]
45
45
  done
46
46
  end
47
47
  end
@@ -57,7 +57,7 @@ describe WorkerRoulette do
57
57
  extra_headers = {'foo' => 'bars'}
58
58
  subject.enqueue_work_order(work_orders, extra_headers) do
59
59
  work_orders_with_headers['headers'].merge!(extra_headers)
60
- redis.lrange(sender, 0, -1).should == [Oj.dump(work_orders_with_headers)]
60
+ redis.lrange(sender, 0, -1).should == [WorkerRoulette.dump(work_orders_with_headers)]
61
61
  done
62
62
  end
63
63
  end
@@ -139,7 +139,7 @@ describe WorkerRoulette do
139
139
  end
140
140
  end
141
141
 
142
- context Tradesman do
142
+ context "Evented Tradesman" do
143
143
  let(:foreman) {WorkerRoulette.a_foreman(sender)}
144
144
  let(:subject) {WorkerRoulette.a_tradesman}
145
145
 
@@ -266,16 +266,10 @@ describe WorkerRoulette do
266
266
  end
267
267
  end
268
268
 
269
- it "should return a hash with a string in the payload if OJ cannot parse the json" do
269
+ xit "should return a hash with a string in the payload if OJ cannot parse the json" do
270
270
 
271
271
  end
272
272
 
273
- context "Potential Ack Success/Failure for Processing Queues" do
274
- xit "should not delete the messages from the queue until they have been processed succcesfully"
275
- xit "should checkout a readlock for a queue and put it back when its done processing; lock should expire after 5 minutes?"
276
- xit "should retry doing work on a queue 3 times if it is locked (ex backoff)"
277
- end
278
-
279
273
  context "Failure" do
280
274
  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; done; end
281
275
  end
@@ -7,7 +7,7 @@ describe WorkerRoulette do
7
7
  let(:hello_work_order) {Hash['payload' => "hello"]}
8
8
  let(:foreman_work_order) {Hash['payload' => "foreman"]}
9
9
  let(:work_orders_with_headers) {default_headers.merge({'payload' => work_orders})}
10
- let(:jsonized_work_orders_with_headers) {[Oj.dump(work_orders_with_headers)]}
10
+ let(:jsonized_work_orders_with_headers) {[WorkerRoulette.dump(work_orders_with_headers)]}
11
11
 
12
12
  let(:redis) {Redis.new(WorkerRoulette.redis_config)}
13
13
 
@@ -26,20 +26,15 @@ describe WorkerRoulette do
26
26
  subject.sender.should == sender
27
27
  end
28
28
 
29
- it "should be injected with a raw_redis_client so it can do is work" do
30
- Redis.any_instance.should_receive(:rpush)
31
- subject.enqueue_work_order(:whatever)
32
- end
33
-
34
29
  it "should enqueue_work_order two work_orders in the sender's slot in the switchboard" do
35
- subject.enqueue_work_order(work_orders.first)
36
- subject.enqueue_work_order(work_orders.last)
37
- redis.lrange(sender, 0, -1).should == work_orders.map {|m| Oj.dump(default_headers.merge({'payload' => m})) }
30
+ subject.enqueue_work_order(work_orders.first) {}
31
+ subject.enqueue_work_order(work_orders.last) {}
32
+ redis.lrange(sender, 0, -1).should == work_orders.map {|m| WorkerRoulette.dump(default_headers.merge({'payload' => m})) }
38
33
  end
39
34
 
40
35
  it "should enqueue_work_order an array of work_orders without headers in the sender's slot in the switchboard" do
41
36
  subject.enqueue_work_order_without_headers(work_orders)
42
- redis.lrange(sender, 0, -1).should == [Oj.dump(work_orders)]
37
+ redis.lrange(sender, 0, -1).should == [WorkerRoulette.dump(work_orders)]
43
38
  end
44
39
 
45
40
  it "should enqueue_work_order an array of work_orders with default headers in the sender's slot in the switchboard" do
@@ -51,26 +46,24 @@ describe WorkerRoulette do
51
46
  extra_headers = {'foo' => 'bars'}
52
47
  subject.enqueue_work_order(work_orders, extra_headers)
53
48
  work_orders_with_headers['headers'].merge!(extra_headers)
54
- redis.lrange(sender, 0, -1).should == [Oj.dump(work_orders_with_headers)]
49
+ redis.lrange(sender, 0, -1).should == [WorkerRoulette.dump(work_orders_with_headers)]
55
50
  end
56
51
 
57
52
  it "should post the sender's id to the job board with an order number" do
58
53
  subject.enqueue_work_order(work_orders.first)
59
- subject.enqueue_work_order(work_orders.last)
60
- redis.zrange(subject.job_board_key, 0, -1, with_scores: true).should == [[sender.to_s, work_orders.length.to_f]]
61
- end
62
-
63
- it "should post the sender_id and work_orders transactionally" do
64
- Redis.any_instance.should_receive(:multi)
65
- subject.enqueue_work_order(work_orders.first)
54
+ WorkerRoulette.foreman('other_forman').enqueue_work_order(work_orders.last)
55
+ redis.zrange(subject.job_board_key, 0, -1, with_scores: true).should == [[sender, 1.0], ["other_forman", 2.0]]
66
56
  end
67
57
 
68
- it "should generate sequential order numbers" do
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')
69
60
  redis.get(subject.counter_key).should == nil
70
61
  subject.enqueue_work_order(work_orders.first)
71
62
  redis.get(subject.counter_key).should == "1"
72
63
  subject.enqueue_work_order(work_orders.last)
73
- redis.get(subject.counter_key).should == "2"
64
+ redis.get(subject.counter_key).should == "1"
65
+ other_forman.enqueue_work_order(work_orders.last)
66
+ redis.get(other_forman.counter_key).should == "2"
74
67
  end
75
68
 
76
69
  it "should publish a notification that a new job is ready" do
@@ -104,11 +97,6 @@ describe WorkerRoulette do
104
97
  subject.sender.should == sender
105
98
  end
106
99
 
107
- it "should be injected with a redis client so it can do its work" do
108
- Redis.any_instance.should_receive(:lrange).and_call_original
109
- subject.work_orders!
110
- end
111
-
112
100
  it "should drain one set of work_orders from the sender's slot in the switchboard" do
113
101
  subject.work_orders!.should == [work_orders_with_headers]
114
102
  subject.work_orders!.should == []
@@ -132,11 +120,6 @@ describe WorkerRoulette do
132
120
  redis.zrange(subject.job_board_key, 0, -1).should == [most_recent_sender]
133
121
  end
134
122
 
135
- it "should get the sender and work_order list transactionally" do
136
- Redis.any_instance.should_receive(:multi).and_call_original
137
- subject.work_orders!
138
- end
139
-
140
123
  it "should get the work_orders from the next queue when a new job is ready" do
141
124
  subject.work_orders!
142
125
  subject.should_receive(:work_orders!).and_call_original
@@ -168,9 +151,6 @@ describe WorkerRoulette do
168
151
  end
169
152
  end
170
153
 
171
- it "should checkout a readlock for a queue and put it back when its done processing; lock should expire after 5 minutes?"
172
- it "should eves drop on the job board"
173
-
174
154
  context "Failure" do
175
155
  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
176
156
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: worker_roulette
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -250,7 +250,6 @@ files:
250
250
  - README.md
251
251
  - Rakefile
252
252
  - lib/worker_roulette.rb
253
- - lib/worker_roulette/a_foreman.rb
254
253
  - lib/worker_roulette/a_tradesman.rb
255
254
  - lib/worker_roulette/foreman.rb
256
255
  - lib/worker_roulette/lua.rb
@@ -1,40 +0,0 @@
1
- require_relative './foreman'
2
- module WorkerRoulette
3
- class AForeman < Foreman
4
- def enqueue_work_order_without_headers(work_order, &callback)
5
- Lua.call(self.class.lua_enqueue_work_orders, [COUNTER_KEY, job_board_key, sender_key, @channel],
6
- [@sender, Oj.dump(work_order), WorkerRoulette::JOB_NOTIFICATIONS], &callback)
7
- end
8
-
9
- private
10
- def self.lua_enqueue_work_orders
11
- <<-HERE
12
- local counter_key = KEYS[1]
13
- local job_board_key = KEYS[2]
14
- local sender_key = KEYS[3]
15
- local channel = KEYS[4]
16
-
17
- local sender = ARGV[1]
18
- local work_order = ARGV[2]
19
- local job_notification = ARGV[3]
20
-
21
- local function enqueue_work_orders(sender, work_order, job_notification)
22
- local result = sender .. ' updated'
23
- local sender_on_job_board = redis.call('ZSCORE', job_board_key, sender_key)
24
-
25
- if (sender_on_job_board == false) then
26
- local count = redis.call('INCR', counter_key)
27
- local job_added = redis.call('ZADD',job_board_key, count, sender_key)
28
- result = sender .. ' added'
29
- end
30
-
31
- local work_added = redis.call('RPUSH',sender_key, work_order)
32
- local job_board_update = redis.call('PUBLISH', channel, job_notification)
33
- return result
34
- end
35
-
36
- return enqueue_work_orders(sender, work_order, job_notification)
37
- HERE
38
- end
39
- end
40
- end