gru 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 89ae1e251f9db9637786d27b5abeb7de7fd0bef7
4
- data.tar.gz: 0dbd72c564a5622ec09abd483d408c7c851e072b
3
+ metadata.gz: c8569b8dac503cf08983a463bb293a277f09f301
4
+ data.tar.gz: 45da184cdbe70af5c0f871d65a9d4f60de2555f6
5
5
  SHA512:
6
- metadata.gz: b3740b2ee29bc4f65968eedd061d5f6fb506a24152088329e7297ecc519b67f8f1f044b03fe515a185987a09691b7b0bf564a9fa0cc2801adca8072df8fd2796
7
- data.tar.gz: f360078d5e374287902e5ce48d78cd6015dd7a83bf986b993ad5a771f2dda556cc64335848f48f81e2dbfe800b3f15f2af04255b013b5e9ff5efc30e4774384c
6
+ metadata.gz: ad6bc8c502243e5f9f8ce86dfe6275758f4eff9ad55f562d070ad99484782f58d1bb49730413d3314e42c5dd92b8fb6f4950a9c290fb97d1168692fd168a264a
7
+ data.tar.gz: 21d48ee74d9fc7bda158b7f2485bbb97ba35b6e9401bbc2a306070a802262f8ae7a78c65df7fdb0d552d6e013cdffcedd95989cd61719e59b10c31cdab60fea8
@@ -190,24 +190,24 @@ module Gru
190
190
  host_running,global_running,host_max,global_max = worker_counts(worker)
191
191
  result = false
192
192
  if rebalance_cluster?
193
- result = host_running.to_i < max_workers_per_host(global_max,host_max) &&
194
- host_running.to_i < @settings.max_worker_processes_per_host
193
+ result = host_running.to_i < max_workers_per_host(global_max,host_max)
195
194
  else
196
195
  result = host_running.to_i < host_max.to_i
197
196
  end
198
- result && global_running.to_i < global_max.to_i
197
+ result && global_running.to_i < global_max.to_i &&
198
+ total_host_running < @settings.max_worker_processes_per_host
199
199
  end
200
200
 
201
201
  def expire_worker?(worker)
202
202
  host_running,global_running,host_max,global_max = worker_counts(worker)
203
203
  result = false
204
204
  if rebalance_cluster?
205
- result = host_running.to_i > max_workers_per_host(global_max,host_max) ||
206
- host_running.to_i > @settings.max_worker_processes_per_host
205
+ result = host_running.to_i > max_workers_per_host(global_max,host_max)
207
206
  else
208
207
  result = host_running.to_i > host_max.to_i
209
208
  end
210
- (result || global_running.to_i > global_max.to_i) && host_running.to_i >= 0
209
+ (result || global_running.to_i > global_max.to_i) && host_running.to_i >= 0 ||
210
+ total_host_running > @settings.max_worker_processes_per_host
211
211
  end
212
212
 
213
213
  def worker_counts(worker)
@@ -232,6 +232,10 @@ module Gru
232
232
  send_message(:hget,host_workers_running_key,worker).to_i
233
233
  end
234
234
 
235
+ def total_host_running
236
+ send_message(:hgetall,host_workers_running_key).values.reduce(0) {|sum, value| sum + value.to_i }
237
+ end
238
+
235
239
  def gru_host_count
236
240
  send_message(:keys,"#{gru_key}:*:workers_running").count - 1
237
241
  end
@@ -1,3 +1,3 @@
1
1
  module Gru
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
@@ -84,6 +84,7 @@ describe Gru::Adapters::RedisAdapter do
84
84
  expect(client).to receive(:setnx).exactly(3).times.and_return(true)
85
85
  expect(client).to receive(:del).with("#{gru_key}:test_worker").exactly(3).times
86
86
  expect(client).to receive(:get).with("#{gru_key}:rebalance").exactly(3).times
87
+ expect(client).to receive(:hgetall).with("#{gru_key}:#{hostname}:workers_running").exactly(3).times.and_return({'test_worker' => '1'})
87
88
  expect(client).to receive(:hincrby).with("#{gru_key}:global:workers_running",'test_worker',1).exactly(3).times
88
89
  expect(client).to receive(:hincrby).with("#{gru_key}:#{hostname}:workers_running",'test_worker',1).exactly(3).times
89
90
  expect(client).to receive(:hget).with("#{gru_key}:#{hostname}:max_workers",'test_worker').exactly(2).times
@@ -99,6 +100,7 @@ describe Gru::Adapters::RedisAdapter do
99
100
  expect(client).to receive(:setnx).exactly(3).times.and_return(true)
100
101
  expect(client).to receive(:del).with("#{gru_key}:test_worker").exactly(3).times
101
102
  expect(client).to receive(:get).with("#{gru_key}:rebalance").exactly(3).times
103
+ expect(client).to receive(:hgetall).with("#{gru_key}:#{hostname}:workers_running").exactly(3).times.and_return({'test_worker' => '1'})
102
104
  expect(client).to receive(:hincrby).with("#{gru_key}:global:workers_running",'test_worker',1).exactly(3).times
103
105
  expect(client).to receive(:hincrby).with("#{gru_key}:#{hostname}:workers_running",'test_worker',1).exactly(3).times
104
106
  expect(client).to receive(:hget).with("#{gru_key}:#{hostname}:max_workers",'test_worker').exactly(2).times
@@ -189,11 +191,13 @@ describe Gru::Adapters::RedisAdapter do
189
191
 
190
192
  it "doesn't remove workers when local maximum has not been exceeded" do
191
193
  expect(client).to receive(:multi).exactly(1).times.and_yield(client).and_return([3,3,4,3])
194
+ expect(client).to receive(:hgetall).with("#{gru_key}:#{hostname}:workers_running").exactly(1).times.and_return({'test_worker' => '1'})
192
195
  expect(adapter.expire_workers).to eq({'test_worker' => 0})
193
196
  end
194
197
 
195
198
  it "doesn't remove workers when global maximum has not been exceeded" do
196
199
  expect(client).to receive(:multi).exactly(1).times.and_yield(client).and_return([3,4,3,5])
200
+ expect(client).to receive(:hgetall).with("#{gru_key}:#{hostname}:workers_running").exactly(1).times.and_return({'test_worker' => '1'})
197
201
  expect(adapter.expire_workers).to eq({'test_worker' => 0})
198
202
  end
199
203
  end
@@ -220,6 +224,7 @@ describe Gru::Adapters::RedisAdapter do
220
224
  expect(client).to receive(:hget).with("#{gru_key}:#{hostname}:max_workers",'test_worker').exactly(3).times
221
225
  expect(client).to receive(:hget).with("#{gru_key}:global:max_workers",'test_worker').exactly(3).times
222
226
  expect(client).to receive(:keys).with("#{gru_key}:*:workers_running").exactly(3).times.and_return(['foo'])
227
+ expect(client).to receive(:hgetall).with("#{gru_key}:#{hostname}:workers_running").exactly(3).times.and_return({'test_worker' => '1'})
223
228
  expect(client).to receive(:setnx).exactly(3).times.and_return(true)
224
229
  expect(client).to receive(:hincrby).with("#{gru_key}:global:workers_running",'test_worker',1).exactly(3).times
225
230
  expect(client).to receive(:hincrby).with("#{gru_key}:#{hostname}:workers_running",'test_worker',1).exactly(3).times
@@ -233,6 +238,7 @@ describe Gru::Adapters::RedisAdapter do
233
238
  expect(client).to receive(:hgetall).with("#{gru_key}:#{hostname}:max_workers").and_return(config.cluster_maximums)
234
239
  expect(client).to receive(:keys).with("#{gru_key}:*:workers_running").exactly(3).times.and_return(["test1","test2"])
235
240
  expect(client).to receive(:get).with("#{gru_key}:rebalance").exactly(3).times.and_return("true")
241
+ expect(client).to receive(:hgetall).with("#{gru_key}:#{hostname}:workers_running").exactly(3).times.and_return({'test_worker' => '10'})
236
242
  expect(client).to receive(:hget).with("#{gru_key}:#{hostname}:max_workers",'test_worker').exactly(3).times
237
243
  expect(client).to receive(:hget).with("#{gru_key}:global:max_workers",'test_worker').exactly(3).times
238
244
  expect(client).to receive(:hget).with("#{gru_key}:#{hostname}:workers_running",'test_worker').exactly(3).times
@@ -245,6 +251,8 @@ describe Gru::Adapters::RedisAdapter do
245
251
  expect(client).to receive(:multi).exactly(3).times.and_yield(client).and_return([9,20,20,30], [10,20,20,30])
246
252
  expect(client).to receive(:hgetall).with("#{gru_key}:#{hostname}:max_workers").and_return(config.cluster_maximums)
247
253
  expect(client).to receive(:setnx).exactly(1).times.and_return(true)
254
+ expect(client).to receive(:hgetall).with("#{gru_key}:#{hostname}:workers_running").exactly(3).times.and_return(
255
+ {'test_worker' => '9'}, {'test_worker' => '10'}, {'test_worker' => '10'})
248
256
  expect(client).to receive(:hincrby).with("#{gru_key}:foo:workers_running",'test_worker',1).exactly(1).times
249
257
  expect(client).to receive(:hincrby).with("#{gru_key}:global:workers_running",'test_worker',1).exactly(1).times
250
258
  expect(client).to receive(:del).with("#{gru_key}:test_worker").exactly(1).times
@@ -8,7 +8,6 @@ require 'pry'
8
8
  # This requires a redis server instance running on localhost
9
9
  # un-pend to run with actual redis-server
10
10
  xdescribe Gru do
11
-
12
11
  after {
13
12
  client.flushdb
14
13
  }
@@ -167,5 +166,323 @@ xdescribe Gru do
167
166
  test_client.hset("GRU:default:default:heartbeats", 'test3', Time.now - 300)
168
167
  expect(test2.adjust_workers).to eq( { 'test_worker' => 3 })
169
168
  end
169
+
170
+ end
171
+
172
+ context "max workers per host with high maximum worker count" do
173
+ let(:settings) {
174
+ {
175
+ rebalance_flag: true,
176
+ manage_worker_heartbeats: true,
177
+ max_workers_per_host: nil,
178
+ cluster_maximums: {
179
+ 'test_worker' => '100'
180
+ }
181
+ }
182
+ }
183
+
184
+ let(:test_client) {
185
+ Redis.new
186
+ }
187
+
188
+ let(:adapter1) {
189
+ adapter1 = Gru::Adapters::RedisAdapter.new(Gru::Configuration.new(settings.clone))
190
+ allow(adapter1).to receive(:hostname).and_return('test1')
191
+ adapter1
192
+ }
193
+
194
+ let(:adapter2) {
195
+ adapter2 = Gru::Adapters::RedisAdapter.new(Gru::Configuration.new(settings.clone))
196
+ allow(adapter2).to receive(:hostname).and_return('test2')
197
+ adapter2
198
+ }
199
+
200
+ let(:adapter3) {
201
+ adapter3 = Gru::Adapters::RedisAdapter.new(Gru::Configuration.new(settings.clone))
202
+ allow(adapter3).to receive(:hostname).and_return('test3')
203
+ adapter3
204
+ }
205
+
206
+ let(:adapter4) {
207
+ adapter4 = Gru::Adapters::RedisAdapter.new(Gru::Configuration.new(settings.clone))
208
+ allow(adapter4).to receive(:hostname).and_return('test4')
209
+ adapter4
210
+ }
211
+
212
+ it "doesn't exceed max processes per host setting" do
213
+ test1 = Gru::WorkerManager.new(adapter1)
214
+ test2 = Gru::WorkerManager.new(adapter2)
215
+ test3 = Gru::WorkerManager.new(adapter3)
216
+ test1.register_workers
217
+ test2.register_workers
218
+ test3.register_workers
219
+ expect(test1.adjust_workers).to eq( { 'test_worker' => 30 })
220
+ expect(test2.adjust_workers).to eq( { 'test_worker' => 30 })
221
+ expect(test3.adjust_workers).to eq( { 'test_worker' => 30 })
222
+ end
223
+
224
+ it "honors the max processes per host setting and correctly rebalances worker counts" do
225
+ test1 = Gru::WorkerManager.new(adapter1)
226
+ test2 = Gru::WorkerManager.new(adapter2)
227
+ test3 = Gru::WorkerManager.new(adapter3)
228
+ test4 = Gru::WorkerManager.new(adapter4)
229
+ test1.register_workers
230
+ test2.register_workers
231
+ test3.register_workers
232
+ # Honors max processes per host setting
233
+ expect(test1.adjust_workers).to eq({ 'test_worker' => 30 })
234
+ expect(test2.adjust_workers).to eq({ 'test_worker' => 30 })
235
+ expect(test3.adjust_workers).to eq({ 'test_worker' => 30 })
236
+ test4.register_workers
237
+ # Pick up remaining workers
238
+ expect(test4.adjust_workers).to eq({ 'test_worker' => 10 })
239
+ # Rebalance workers across hosts
240
+ expect(test3.adjust_workers).to eq({ 'test_worker' => -5 })
241
+ expect(test2.adjust_workers).to eq({ 'test_worker' => -5 })
242
+ expect(test1.adjust_workers).to eq({ 'test_worker' => -5 })
243
+ expect(test4.adjust_workers).to eq({ 'test_worker' => 15 })
244
+ # No more workers to pick up on the hosts
245
+ expect(test4.adjust_workers).to eq({ 'test_worker' => 0 })
246
+ expect(test3.adjust_workers).to eq({ 'test_worker' => 0 })
247
+ expect(test2.adjust_workers).to eq({ 'test_worker' => 0 })
248
+ expect(test1.adjust_workers).to eq({ 'test_worker' => 0 })
249
+ expect(test4.adjust_workers).to eq({ 'test_worker' => 0 })
250
+ # Release workers
251
+ test4.release_workers
252
+ # Rebalance for lost host
253
+ expect(test1.adjust_workers).to eq({ 'test_worker' => 5 })
254
+ expect(test2.adjust_workers).to eq({ 'test_worker' => 5 })
255
+ expect(test3.adjust_workers).to eq({ 'test_worker' => 5 })
256
+ # No more workers due to max per host limit
257
+ expect(test1.adjust_workers).to eq({ 'test_worker' => 0 })
258
+ expect(test2.adjust_workers).to eq({ 'test_worker' => 0 })
259
+ expect(test3.adjust_workers).to eq({ 'test_worker' => 0 })
260
+ end
261
+
262
+ end
263
+
264
+ context "max workers per host with high maximum worker count" do
265
+ let(:settings) {
266
+ {
267
+ rebalance_flag: true,
268
+ manage_worker_heartbeats: true,
269
+ max_workers_per_host: 5,
270
+ cluster_maximums: {
271
+ 'test_worker1' => '3',
272
+ 'test_worker2' => '3',
273
+ 'test_worker3' => '3',
274
+ 'test_worker4' => '3',
275
+ 'test_worker5' => '3',
276
+ 'test_worker6' => '3'
277
+ }
278
+ }
279
+ }
280
+
281
+ let(:test_client) {
282
+ Redis.new
283
+ }
284
+
285
+ let(:adapter1) {
286
+ adapter1 = Gru::Adapters::RedisAdapter.new(Gru::Configuration.new(settings.clone))
287
+ allow(adapter1).to receive(:hostname).and_return('test1')
288
+ adapter1
289
+ }
290
+
291
+ let(:adapter2) {
292
+ adapter2 = Gru::Adapters::RedisAdapter.new(Gru::Configuration.new(settings.clone))
293
+ allow(adapter2).to receive(:hostname).and_return('test2')
294
+ adapter2
295
+ }
296
+
297
+ let(:adapter3) {
298
+ adapter3 = Gru::Adapters::RedisAdapter.new(Gru::Configuration.new(settings.clone))
299
+ allow(adapter3).to receive(:hostname).and_return('test3')
300
+ adapter3
301
+ }
302
+
303
+ let(:adapter4) {
304
+ adapter4 = Gru::Adapters::RedisAdapter.new(Gru::Configuration.new(settings.clone))
305
+ allow(adapter4).to receive(:hostname).and_return('test4')
306
+ adapter4
307
+ }
308
+
309
+ it "handles provisioning with many workers and few worker instances" do
310
+ test1 = Gru::WorkerManager.new(adapter1)
311
+ test2 = Gru::WorkerManager.new(adapter2)
312
+ test3 = Gru::WorkerManager.new(adapter3)
313
+ test4 = Gru::WorkerManager.new(adapter4)
314
+ test1.register_workers
315
+ test2.register_workers
316
+ test3.register_workers
317
+ # Honors max processes per host setting
318
+ expect(test1.adjust_workers).to eq({
319
+ 'test_worker1' => 1,
320
+ 'test_worker2' => 1,
321
+ 'test_worker3' => 1,
322
+ 'test_worker4' => 1,
323
+ 'test_worker5' => 1,
324
+ 'test_worker6' => 0
325
+ })
326
+
327
+ expect(test2.adjust_workers).to eq({
328
+ 'test_worker1' => 1,
329
+ 'test_worker2' => 1,
330
+ 'test_worker3' => 1,
331
+ 'test_worker4' => 1,
332
+ 'test_worker5' => 1,
333
+ 'test_worker6' => 0
334
+ })
335
+
336
+ expect(test3.adjust_workers).to eq({
337
+ 'test_worker1' => 1,
338
+ 'test_worker2' => 1,
339
+ 'test_worker3' => 1,
340
+ 'test_worker4' => 1,
341
+ 'test_worker5' => 1,
342
+ 'test_worker6' => 0
343
+ })
344
+ test4.register_workers
345
+ # Adds new worker based on new instance
346
+ expect(test4.adjust_workers).to eq({
347
+ 'test_worker1' => 0,
348
+ 'test_worker2' => 0,
349
+ 'test_worker3' => 0,
350
+ 'test_worker4' => 0,
351
+ 'test_worker5' => 0,
352
+ 'test_worker6' => 1
353
+ })
354
+
355
+ # Doesn't alter existing worker instances
356
+ # due to max_workers_per_host balance
357
+ expect(test1.adjust_workers).to eq({
358
+ 'test_worker1' => 0,
359
+ 'test_worker2' => 0,
360
+ 'test_worker3' => 0,
361
+ 'test_worker4' => 0,
362
+ 'test_worker5' => 0,
363
+ 'test_worker6' => 0
364
+ })
365
+ end
366
+
367
+ it "handles expiring with many workers and few worker instances" do
368
+ test1 = Gru::WorkerManager.new(adapter1)
369
+ test1.register_workers
370
+ args = ["GRU:default:default:test1:workers_running",
371
+ 'test_worker1',1,'test_worker2',1,'test_worker3',1,
372
+ 'test_worker4',1,'test_worker5',1,'test_worker6',1
373
+ ]
374
+ client.hmset(*args)
375
+
376
+ # Honors max processes per host setting
377
+ expect(test1.adjust_workers).to eq({
378
+ 'test_worker1' => -1,
379
+ 'test_worker2' => 0,
380
+ 'test_worker3' => 0,
381
+ 'test_worker4' => 0,
382
+ 'test_worker5' => 0,
383
+ 'test_worker6' => 0
384
+ })
385
+
386
+ expect(test1.adjust_workers).to eq({
387
+ 'test_worker1' => 0,
388
+ 'test_worker2' => 0,
389
+ 'test_worker3' => 0,
390
+ 'test_worker4' => 0,
391
+ 'test_worker5' => 0,
392
+ 'test_worker6' => 0
393
+ })
394
+ end
395
+ end
396
+ context "max workers per host without rebalance flag" do
397
+ let(:settings) {
398
+ {
399
+ rebalance_flag: false,
400
+ manage_worker_heartbeats: true,
401
+ max_workers_per_host: 5,
402
+ cluster_maximums: {
403
+ 'test_worker1' => '3',
404
+ 'test_worker2' => '3',
405
+ 'test_worker3' => '3',
406
+ 'test_worker4' => '3',
407
+ 'test_worker5' => '3',
408
+ 'test_worker6' => '3'
409
+ }
410
+ }
411
+ }
412
+
413
+ let(:test_client) {
414
+ Redis.new
415
+ }
416
+
417
+ let(:adapter1) {
418
+ adapter1 = Gru::Adapters::RedisAdapter.new(Gru::Configuration.new(settings.clone))
419
+ allow(adapter1).to receive(:hostname).and_return('test1')
420
+ adapter1
421
+ }
422
+
423
+ let(:adapter2) {
424
+ adapter2 = Gru::Adapters::RedisAdapter.new(Gru::Configuration.new(settings.clone))
425
+ allow(adapter2).to receive(:hostname).and_return('test2')
426
+ adapter2
427
+ }
428
+
429
+ let(:adapter3) {
430
+ adapter3 = Gru::Adapters::RedisAdapter.new(Gru::Configuration.new(settings.clone))
431
+ allow(adapter3).to receive(:hostname).and_return('test3')
432
+ adapter3
433
+ }
434
+
435
+ let(:adapter4) {
436
+ adapter4 = Gru::Adapters::RedisAdapter.new(Gru::Configuration.new(settings.clone))
437
+ allow(adapter4).to receive(:hostname).and_return('test4')
438
+ adapter4
439
+ }
440
+
441
+ it "honors the max workers per host setting" do
442
+ test1 = Gru::WorkerManager.new(adapter1)
443
+ test2 = Gru::WorkerManager.new(adapter2)
444
+ test3 = Gru::WorkerManager.new(adapter3)
445
+ test4 = Gru::WorkerManager.new(adapter4)
446
+ test1.register_workers
447
+ test2.register_workers
448
+ test3.register_workers
449
+ # Honors max processes per host setting
450
+ expect(test1.adjust_workers).to eq({
451
+ 'test_worker1' => 3,
452
+ 'test_worker2' => 2,
453
+ 'test_worker3' => 0,
454
+ 'test_worker4' => 0,
455
+ 'test_worker5' => 0,
456
+ 'test_worker6' => 0
457
+ })
458
+
459
+ expect(test2.adjust_workers).to eq({
460
+ 'test_worker1' => 0,
461
+ 'test_worker2' => 1,
462
+ 'test_worker3' => 3,
463
+ 'test_worker4' => 1,
464
+ 'test_worker5' => 0,
465
+ 'test_worker6' => 0
466
+ })
467
+
468
+ expect(test3.adjust_workers).to eq({
469
+ 'test_worker1' => 0,
470
+ 'test_worker2' => 0,
471
+ 'test_worker3' => 0,
472
+ 'test_worker4' => 2,
473
+ 'test_worker5' => 3,
474
+ 'test_worker6' => 0
475
+ })
476
+
477
+ test4.register_workers
478
+ expect(test4.adjust_workers).to eq({
479
+ 'test_worker1' => 0,
480
+ 'test_worker2' => 0,
481
+ 'test_worker3' => 0,
482
+ 'test_worker4' => 0,
483
+ 'test_worker5' => 0,
484
+ 'test_worker6' => 3
485
+ })
486
+ end
170
487
  end
171
488
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gru
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeffrey Gillis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-04-21 00:00:00.000000000 Z
11
+ date: 2016-04-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis