boy_band 0.1.6 → 0.1.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/boy_band.rb +132 -24
  3. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d7584b735b0671735458dcf190fac4d6469b4fc3e165e9df54f909bceaa89b83
4
- data.tar.gz: 691d966ef8eabf44ec431cf4a182ca81b10202c17f96c0f88d5a702ff6492eb6
3
+ metadata.gz: 6931c59174a8d6eda05b764b143c11c38532c46ae0d68f41b35700539db6e45a
4
+ data.tar.gz: 7df882de888ee4ac4680d37006f437d5b26e9055f193f596486f6259bb75997e
5
5
  SHA512:
6
- metadata.gz: 06723c500fc807e94c6f1937154033dd87d82f9c3ce53d4cc699a4b6071ddbb3f180100a2d9a0cb002dee06b87c9a8248326b8de84cf03953d54423e8e44197e
7
- data.tar.gz: 61166b0bc26eae3181cbf10f195bfb461199cc0f40839f7717a8765abac549dc632826bf2160dc4fef5bff08fec1ffb8c528c999746da2e3b5cfcdb47105329e
6
+ metadata.gz: 2c19f3dd8e840f87b903d97450adbbfe0ce92b236cbbdec0905b7e6f18c283dcf2dccc2372f731cfbcc53bde6e530e79061b6da072b1cf49f61fe1ab461daeb4
7
+ data.tar.gz: 41cbb91e46bc9dcb8169c95c5b0b458626692679fa21668a09281d2f4a40568c7595917f8ac35268612c674470ea09bda8c557c85ba931a475bfd068dd22167a
@@ -39,12 +39,22 @@ module BoyBand
39
39
  def set_job_chain(val)
40
40
  @@job_chain = val
41
41
  end
42
+
43
+ def queue_size(queue)
44
+ size = Resque.redis.get("sizeof/#{queue}").to_i
45
+ if !size || size == 0
46
+ size = Resque.size(queue)
47
+ Resque.redis.setex("sizeof/#{queue}", 30.seconds.to_i, size)
48
+ end
49
+ size
50
+ end
42
51
 
43
52
  def schedule_for(queue, klass, method_name, *args)
53
+ queue = queue.to_sym
44
54
  @queue = queue.to_s
45
55
  job_hash = Digest::MD5.hexdigest(args.to_json)
46
56
  note_job(job_hash)
47
- size = Resque.size(queue)
57
+ size = queue_size(queue)
48
58
  args.push("domain::#{self.domain_id}")
49
59
  chain = self.job_chain.split(/##/)
50
60
  job_id = "j#{Time.now.iso8601}_#{rand(9999)}"
@@ -53,10 +63,19 @@ module BoyBand
53
63
  Resque.redis.incr("jobs_from_#{chain[0]}")
54
64
  Resque.redis.expire("jobs_from_#{chain[0]}", 24.hours.to_i)
55
65
  end
56
- chain.push("#{klass.to_s},#{method_name.to_s},#{args.join('+')}")
57
- Rails.logger.warn("jobchain set, #{chain[0]} #{chain.join('##')}") if chain.length > 1
66
+ Resque.redis.setex("scheduled/#{klass.to_s}/#{job_hash}", 6.hours, "t")
67
+ chain_args = args[0..-2]
68
+ if chain_args.length == 1 && chain_args[0].is_a?(Hash)
69
+ chain_args = [chain_args[0]['method'],chain_args[0]['id'],chain_args[0]['arguments'].to_s[0, 20]]
70
+ end
71
+ chain.push("#{klass.to_s},#{method_name.to_s},#{chain_args.join('+')}")
72
+ Rails.logger.warn("jobchain set, #{chain[0]} #{chain.join('##')}") if chain.length > 2
58
73
  if chain.length > 5
59
- Rails.logger.error("jobchain too long: job_id, #{chain.length} entries")
74
+ Rails.logger.error("jobchain too deep: #{chain[0]}, #{chain.length} entries")
75
+ end
76
+ job_count = Resque.redis.get("jobs_from_#{chain[0]}")
77
+ if job_count && job_count.to_i > 50
78
+ Rails.logger.error("jobchain too many sub-jobs: #{chain[0]}, #{job_count} so far")
60
79
  end
61
80
  args.push("chain::#{chain.join('##')}")
62
81
  if queue == :slow
@@ -75,21 +94,21 @@ module BoyBand
75
94
  end
76
95
 
77
96
  def note_job(hash)
78
- if Resque.redis
79
- timestamps = JSON.parse(Resque.redis.hget('hashed_jobs', hash) || "[]")
80
- cutoff = 6.hours.ago.to_i
81
- timestamps = timestamps.select{|ts| ts > cutoff }
82
- timestamps.push(Time.now.to_i)
83
- # Resque.redis.hset('hashed_jobs', hash, timestamps.to_json)
84
- end
97
+ # if Resque.redis
98
+ # timestamps = JSON.parse(Resque.redis.hget('hashed_jobs', hash) || "[]")
99
+ # cutoff = 6.hours.ago.to_i
100
+ # timestamps = timestamps.select{|ts| ts > cutoff }
101
+ # timestamps.push(Time.now.to_i)
102
+ # # Resque.redis.hset('hashed_jobs', hash, timestamps.to_json)
103
+ # end
85
104
  end
86
105
 
87
106
  def clear_job(hash)
88
- if Resque.redis
89
- timestamps = JSON.parse(Resque.redis.hget('hashed_jobs', hash) || "[]")
90
- timestamps.shift
91
- # Resque.redis.hset('hashed_jobs', hash, timestamps.to_json)
92
- end
107
+ # if Resque.redis
108
+ # timestamps = JSON.parse(Resque.redis.hget('hashed_jobs', hash) || "[]")
109
+ # timestamps.shift
110
+ # # Resque.redis.hset('hashed_jobs', hash, timestamps.to_json)
111
+ # end
93
112
  end
94
113
 
95
114
  def schedule(klass, method_name, *args)
@@ -120,6 +139,7 @@ module BoyBand
120
139
  klass = Object.const_get(klass_string)
121
140
  method_name = args_copy.shift
122
141
  job_hash = Digest::MD5.hexdigest(args_copy.to_json)
142
+ Resque.redis.del("scheduled/#{klass_string}/#{method_name}/#{job_hash}")
123
143
  hash = args_copy[0] if args_copy[0].is_a?(Hash)
124
144
  hash ||= {'method' => method_name}
125
145
  action = "#{klass_string} . #{hash['method']} (#{hash['id']})"
@@ -174,6 +194,68 @@ module BoyBand
174
194
  end
175
195
  res
176
196
  end
197
+
198
+ def root_actions(queue='default')
199
+ idx = Resque.size(queue)
200
+ job_ids = {}
201
+ idx.times do |i|
202
+ item = Resque.peek(queue, i)
203
+ chain = nil
204
+ if item && item['args'] && item['args'][-1].match(/^chain::/)
205
+ chain = item['args'].pop
206
+ end
207
+ if chain
208
+ parts = chain.split(/##/)
209
+ job_ids[parts[0]] ||= [parts[1], 0, []]
210
+ job_ids[parts[0]][1] += 1
211
+ job_ids[parts[0]][2] << parts.length - 2
212
+ end
213
+ end
214
+ job_ids.each{|k, v| job_ids.delete(k) if v[1] <= 5}.length
215
+ job_ids
216
+ end
217
+
218
+ def action_types(queue='default')
219
+ idx = Resque.size(queue)
220
+ list = []
221
+ idx.times do |i|
222
+ item = Resque.peek(queue, i)
223
+ chain = nil
224
+ if item && item['args'] && item['args'][-1].match(/^chain::/)
225
+ chain = item['args'].pop
226
+ end
227
+ if chain
228
+ match = chain.scan(/##/)
229
+ if match && match.length == 1
230
+ item['root'] = true
231
+ list << item
232
+ elsif match && match.length > 1
233
+ list << item
234
+ end
235
+ end
236
+ end
237
+ count = {'root' => {}, 'non_root' => {}}
238
+ list.each do |item|
239
+ key = "#{item['args'][0]}::#{item['args'][2].is_a?(Hash) ? item['args'][2]['method'] : item['args'][1]}"
240
+ count[item['root'] ? 'root' : 'non_root'][key] ||= 0
241
+ count[item['root'] ? 'root' : 'non_root'][key] += 1
242
+ end.length
243
+ count
244
+ end
245
+
246
+ def find_actions(method)
247
+ queue = 'default'
248
+ idx = Resque.size(queue)
249
+ list = []
250
+ idx.times do |i|
251
+ item = Resque.peek(queue, i)
252
+ if item['args'] && item['args'][2].is_a?(Hash) && item['args'][2]['method'] == method
253
+ list << item
254
+ puts item.to_json
255
+ end
256
+ end
257
+ list
258
+ end
177
259
 
178
260
  def scheduled_for?(queue, klass, method_name, *args)
179
261
  args_copy = [] + args
@@ -184,6 +266,10 @@ module BoyBand
184
266
  set_domain_id(args_copy.pop.split(/::/, 2)[1])
185
267
  end
186
268
 
269
+ idx = queue_size(queue)
270
+ job_hash = args_copy.to_json
271
+ return true if Resque.redis.get("scheduled/#{klass.to_s}/#{method_name}/#{job_hash}") == "t"
272
+ return false if idx > 500 # big queues mustn't be searched this way
187
273
  idx = Resque.size(queue)
188
274
  queue_class = (queue == :slow ? 'SlowWorker' : 'Worker')
189
275
  if false
@@ -308,6 +394,10 @@ module BoyBand
308
394
 
309
395
  module AsyncInstanceMethods
310
396
  def schedule(method, *args)
397
+ schedule_for('default', method, *args)
398
+ end
399
+
400
+ def schedule_for(queue, method, *args)
311
401
  return nil unless method
312
402
  id = self.id
313
403
  settings = {
@@ -316,19 +406,23 @@ module BoyBand
316
406
  'scheduled' => self.class.scheduled_stamp,
317
407
  'arguments' => args
318
408
  }
319
- Worker.schedule(self.class, :perform_action, settings)
409
+ Worker.schedule_for(queue, self.class, :perform_action, settings)
320
410
  end
321
-
411
+
322
412
  def schedule_once(method, *args)
413
+ schedule_once_for('default', method, *args)
414
+ end
415
+
416
+ def schedule_once_for(queue, method, *args)
323
417
  return nil unless method && id
324
- already_scheduled = Worker.scheduled?(self.class, :perform_action, {
418
+ already_scheduled = Worker.scheduled_for?(queue, self.class, :perform_action, {
325
419
  'id' => id,
326
420
  'method' => method,
327
421
  'scheduled' => self.class.scheduled_stamp,
328
422
  'arguments' => args
329
423
  })
330
424
  if !already_scheduled
331
- schedule(method, *args)
425
+ schedule_for(queue, method, *args)
332
426
  else
333
427
  false
334
428
  end
@@ -353,23 +447,37 @@ module BoyBand
353
447
  'scheduled' => self.scheduled_stamp,
354
448
  'arguments' => args
355
449
  }
356
- Worker.schedule(self, :perform_action, settings)
450
+ schedule_for('default', method, *args)
357
451
  end
358
452
 
453
+ def schedule_for(queue, method, *args)
454
+ return nil unless method
455
+ settings = {
456
+ 'method' => method,
457
+ 'scheduled' => self.scheduled_stamp,
458
+ 'arguments' => args
459
+ }
460
+ Worker.schedule_for(queue, self, :perform_action, settings)
461
+ end
462
+
359
463
  def schedule_once(method, *args)
464
+ schedule_once_for('default', method, *args)
465
+ end
466
+
467
+ def schedule_once_for(queue, method, *args)
360
468
  return nil unless method
361
- already_scheduled = Worker.scheduled?(self, :perform_action, {
469
+ already_scheduled = Worker.scheduled_for?(queue, self, :perform_action, {
362
470
  'method' => method,
363
471
  'scheduled' => self.scheduled_stamp,
364
472
  'arguments' => args
365
473
  })
366
474
  if !already_scheduled
367
- schedule(method, *args)
475
+ schedule_for(queue, method, *args)
368
476
  else
369
477
  false
370
478
  end
371
479
  end
372
-
480
+
373
481
  def perform_action(settings)
374
482
  obj = self
375
483
  if settings['id']
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: boy_band
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Whitmer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-13 00:00:00.000000000 Z
11
+ date: 2020-05-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails