canvas_sync 0.17.3.beta3 → 0.17.6.beta1

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
  SHA256:
3
- metadata.gz: 54feabc8f9154b633a70a11d15bfeebaf54ab9d9eb24b9a636c27844728ca1a3
4
- data.tar.gz: 0c8d2692a83ebb37a518f61d11fb2970b3204f3d68c990c721fa23a7365a91b6
3
+ metadata.gz: ce407ae1dd566665cb8ae02856b61f033001cb25aadb903b5e9261846ad9e0c0
4
+ data.tar.gz: 349fa1f9e033101be253f2d5e5b8212f243a9ea28d143e683d6b2b6a877fcac6
5
5
  SHA512:
6
- metadata.gz: 50efdad1e463d363463b72fa2fcc5581f877bdeb2c2440d688b10f451321996d95c7acd610d822fcc943d0220ed5520f4963de12341c1adb4238d131c5d8df04
7
- data.tar.gz: 51d40bc898a58a0aab65a85d4c1820ca5da72bf22b4c11e0ee631ad2e815dc344dc4824a2ade24e7485ace7ad0d12692d71cc93054afcfc05269ac22a4f7b4c9
6
+ metadata.gz: 32f2b3b973fdeec88c0a231112c3b82a275baa97937d3788b865d4eb50147a973022e77271970c3c58eab8a4ddbc4bdf10108d7f4f2df2f13c098d007d3bab67
7
+ data.tar.gz: 854ab10f0092ca6edfb280429c6cb600d8192a5c1189078ecca45a19ec3301c7e6afc3fdceec638ead82e17eab523e5669da010a42cd34761c7753dd06a0d7fb
@@ -99,7 +99,7 @@ module CanvasSync
99
99
  if parent_bid
100
100
  r.hincrby("BID-#{parent_bid}", "children", 1)
101
101
  r.expire("BID-#{parent_bid}", BID_EXPIRE_TTL)
102
- r.sadd("BID-#{parent_bid}-bids", bid)
102
+ r.zadd("BID-#{parent_bid}-bids", created_at, bid)
103
103
  end
104
104
  end
105
105
  end
@@ -151,6 +151,42 @@ module CanvasSync
151
151
  batch.parent ? valid && valid?(batch.parent) : valid
152
152
  end
153
153
 
154
+ def keep_open!
155
+ if block_given?
156
+ begin
157
+ keep_open!
158
+ yield
159
+ ensure
160
+ let_close!
161
+ end
162
+ else
163
+ redis do |r|
164
+ r.hset(@bidkey, 'keep_open', true)
165
+ end
166
+ end
167
+ end
168
+
169
+ def let_close!
170
+ _, failed, pending, children, complete, success = redis do |r|
171
+ r.multi do
172
+ r.hset(@bidkey, 'keep_open', false)
173
+
174
+ r.scard("BID-#{bid}-failed")
175
+ r.hincrby("BID-#{bid}", "pending", 0)
176
+ r.hincrby("BID-#{bid}", "children", 0)
177
+ r.scard("BID-#{bid}-batches-complete")
178
+ r.scard("BID-#{bid}-batches-success")
179
+ end
180
+ end
181
+
182
+ all_success = pending.to_i.zero? && children == success
183
+ # if complete or successfull call complete callback (the complete callback may then call successful)
184
+ if (pending.to_i == failed.to_i && children == complete) || all_success
185
+ self.class.enqueue_callbacks(:complete, bid)
186
+ self.class.enqueue_callbacks(:success, bid) if all_success
187
+ end
188
+ end
189
+
154
190
  def self.with_batch(batch)
155
191
  batch = self.new(batch) if batch.is_a?(String)
156
192
  parent = Thread.current[:batch]
@@ -171,6 +207,13 @@ module CanvasSync
171
207
  @bidkey
172
208
  end
173
209
 
210
+ def flush_pending_attrs
211
+ super
212
+ redis do |r|
213
+ r.zadd("batches", created_at, bid)
214
+ end
215
+ end
216
+
174
217
  private
175
218
 
176
219
  def assert_batch_is_open
@@ -184,15 +227,16 @@ module CanvasSync
184
227
 
185
228
  def append_jobs(jids)
186
229
  jids = jids.uniq
230
+ return unless jids.size > 0
231
+
187
232
  redis do |r|
233
+ tme = Time.now.utc.to_f
234
+ added = r.zadd(@bidkey + "-jids", jids.map{|jid| [tme, jid] }, nx: true)
188
235
  r.multi do
189
- r.hincrby(@bidkey, "pending", jids.size)
236
+ r.hincrby(@bidkey, "pending", added)
237
+ r.hincrby(@bidkey, "job_count", added)
190
238
  r.expire(@bidkey, BID_EXPIRE_TTL)
191
-
192
- if jids.size > 0
193
- r.sadd(@bidkey + "-jids", jids)
194
- r.expire(@bidkey + "-jids", BID_EXPIRE_TTL)
195
- end
239
+ r.expire(@bidkey + "-jids", BID_EXPIRE_TTL)
196
240
  end
197
241
  end
198
242
  end
@@ -200,6 +244,8 @@ module CanvasSync
200
244
  class << self
201
245
  def process_failed_job(bid, jid)
202
246
  _, pending, failed, children, complete, parent_bid = redis do |r|
247
+ return unless r.exists?("BID-#{bid}")
248
+
203
249
  r.multi do
204
250
  r.sadd("BID-#{bid}-failed", jid)
205
251
 
@@ -220,6 +266,8 @@ module CanvasSync
220
266
 
221
267
  def process_dead_job(bid, jid)
222
268
  _, failed, children, complete, parent_bid = redis do |r|
269
+ return unless r.exists?("BID-#{bid}")
270
+
223
271
  r.multi do
224
272
  r.sadd("BID-#{bid}-dead", jid)
225
273
 
@@ -245,7 +293,9 @@ module CanvasSync
245
293
  end
246
294
 
247
295
  def process_successful_job(bid, jid)
248
- _, failed, pending, children, complete, success, parent_bid = redis do |r|
296
+ _, failed, pending, children, complete, success, parent_bid, keep_open = redis do |r|
297
+ return unless r.exists?("BID-#{bid}")
298
+
249
299
  r.multi do
250
300
  r.srem("BID-#{bid}-failed", jid)
251
301
 
@@ -255,15 +305,14 @@ module CanvasSync
255
305
  r.scard("BID-#{bid}-batches-complete")
256
306
  r.scard("BID-#{bid}-batches-success")
257
307
  r.hget("BID-#{bid}", "parent_bid")
308
+ r.hget("BID-#{bid}", "keep_open")
258
309
 
259
310
  r.hincrby("BID-#{bid}", "successful-jobs", 1)
260
- r.srem("BID-#{bid}-jids", jid)
311
+ r.zrem("BID-#{bid}-jids", jid)
261
312
  r.expire("BID-#{bid}", BID_EXPIRE_TTL)
262
313
  end
263
314
  end
264
315
 
265
- # TODO - There seems to be an issue where a :complete callback batch will occasionally run its job, but won't enqueue_callbacks()
266
-
267
316
  all_success = pending.to_i.zero? && children == success
268
317
  # if complete or successfull call complete callback (the complete callback may then call successful)
269
318
  if (pending.to_i == failed.to_i && children == complete) || all_success
@@ -277,6 +326,7 @@ module CanvasSync
277
326
  callback_key = "#{batch_key}-callbacks-#{event}"
278
327
  already_processed, _, callbacks, queue, parent_bid, callback_params = redis do |r|
279
328
  return unless r.exists?(batch_key)
329
+ return if r.hget(batch_key, 'keep_open') == 'true'
280
330
  r.multi do
281
331
  r.hget(batch_key, event)
282
332
  r.hset(batch_key, event, true)
@@ -302,6 +352,11 @@ module CanvasSync
302
352
  if callback_args.present? && !callback_params.present?
303
353
  logger.debug {"Enqueue callback bid: #{bid} event: #{event} args: #{callback_args.inspect}"}
304
354
 
355
+ redis do |r|
356
+ r.sadd("#{batch_key}-pending_callbacks", event)
357
+ r.expire("#{batch_key}-pending_callbacks", BID_EXPIRE_TTL)
358
+ end
359
+
305
360
  with_batch(parent_bid) do
306
361
  cb_batch = self.new
307
362
  cb_batch.callback_params = {
@@ -330,7 +385,8 @@ module CanvasSync
330
385
  def cleanup_redis(bid)
331
386
  logger.debug {"Cleaning redis of batch #{bid}"}
332
387
  redis do |r|
333
- r.del(
388
+ r.zrem("batches", bid)
389
+ r.unlink(
334
390
  "BID-#{bid}",
335
391
  "BID-#{bid}-callbacks-complete",
336
392
  "BID-#{bid}-callbacks-success",
@@ -341,10 +397,21 @@ module CanvasSync
341
397
  "BID-#{bid}-batches-failed",
342
398
  "BID-#{bid}-bids",
343
399
  "BID-#{bid}-jids",
400
+ "BID-#{bid}-pending_callbacks",
344
401
  )
345
402
  end
346
403
  end
347
404
 
405
+ def delete_prematurely!(bid)
406
+ child_bids = redis do |r|
407
+ r.zrange("BID-#{bid}-bids", 0, -1)
408
+ end
409
+ child_bids.each do |cbid|
410
+ delete_prematurely!(cbid)
411
+ end
412
+ cleanup_redis(bid)
413
+ end
414
+
348
415
  def redis(*args, &blk)
349
416
  defined?(::Sidekiq) ? ::Sidekiq.redis(*args, &blk) : nil # TODO
350
417
  end
@@ -353,8 +420,6 @@ module CanvasSync
353
420
  defined?(::Sidekiq) ? ::Sidekiq.logger : Rails.logger
354
421
  end
355
422
 
356
- private
357
-
358
423
  def push_callbacks(args, queue)
359
424
  Batch::Callback::worker_class.enqueue_all(args, queue)
360
425
  end
@@ -10,7 +10,7 @@ module CanvasSync
10
10
  begin
11
11
  Thread.current[:batch] = Batch.new(@bid)
12
12
  block.call
13
- batch&.save_context_changes
13
+ Thread.current[:batch].save_context_changes
14
14
  Batch.process_successful_job(@bid, job_id)
15
15
  rescue
16
16
  Batch.process_failed_job(@bid, job_id)
@@ -52,9 +52,6 @@ module CanvasSync
52
52
 
53
53
  class Finalize
54
54
  def dispatch(status, opts)
55
- is_callback_batch = opts['origin'].present?
56
- has_callback_batch = opts['callback_bid'].present?
57
-
58
55
  bid = opts["bid"]
59
56
  event = opts["event"].to_sym
60
57
 
@@ -63,12 +60,21 @@ module CanvasSync
63
60
  batch_status = Status.new bid
64
61
  send(event, bid, batch_status, batch_status.parent_bid)
65
62
 
66
- if event == :success && !has_callback_batch
67
- Batch.cleanup_redis(bid)
68
- end
69
-
70
- if event == :success && is_callback_batch && opts['origin']['event'].to_sym == :success
71
- Batch.cleanup_redis(opts['origin']['for_bid'])
63
+ if event == :success
64
+ if opts['origin'].present?
65
+ origin_bid = opts['origin']['for_bid']
66
+ _, pending, success_ran = Batch.redis do |r|
67
+ r.multi do
68
+ r.srem("BID-#{origin_bid}-pending_callbacks", opts['origin']['event'])
69
+ r.scard("BID-#{origin_bid}-pending_callbacks")
70
+ r.hget("BID-#{origin_bid}", "success")
71
+ end
72
+ end
73
+ Batch.cleanup_redis(origin_bid) if pending == 0 && success_ran == 'true'
74
+ end
75
+ if (Batch.redis {|r| r.scard("BID-#{bid}-pending_callbacks") }) == 0
76
+ Batch.cleanup_redis(bid)
77
+ end
72
78
  end
73
79
  end
74
80
 
@@ -113,13 +119,7 @@ module CanvasSync
113
119
  end
114
120
  end
115
121
 
116
- # If the batch was successful run :success callback, which will call the parent's :complete callback (if necessary)
117
- # Also, only trigger the success callback if the :complete callback_batch was successful
118
- if pending.to_i.zero? && children == success
119
- # Batch.enqueue_callbacks(:success, bid)
120
-
121
- # otherwise check for a parent and call its :complete if needed
122
- elsif parent_bid
122
+ if parent_bid && !(pending.to_i.zero? && children == success)
123
123
  # if batch was not successfull check and see if its parent is complete
124
124
  # if the parent is complete we trigger the complete callback
125
125
  # We don't want to run this if the batch was successfull because the success
@@ -28,6 +28,10 @@ module CanvasSync
28
28
  @hash_map[local_bid]
29
29
  end
30
30
 
31
+ def own
32
+ resolve_hash(@bid_stack[-1]) || {}
33
+ end
34
+
31
35
  def set_local(new_hash)
32
36
  @dirty = true
33
37
  local.clear.merge!(new_hash)
@@ -106,7 +110,8 @@ module CanvasSync
106
110
  @bid_stack[index]
107
111
  else
108
112
  pbid = Batch.redis do |r|
109
- r.hget("BID-#{bid}", "parent_bid") || r.hget("BID-#{bid}", "callback_for")
113
+ callback_params = JSON.parse(r.hget("BID-#{bid}", "callback_params") || "{}")
114
+ callback_params['for_bid'] || r.hget("BID-#{bid}", "parent_bid")
110
115
  end
111
116
  @bid_stack.unshift(pbid)
112
117
  pbid
@@ -24,6 +24,7 @@ module CanvasSync
24
24
  end
25
25
 
26
26
  def self.from_pid(pid)
27
+ raise "PID must be given" unless pid.present?
27
28
  new(pid)
28
29
  end
29
30
 
@@ -38,7 +39,7 @@ module CanvasSync
38
39
  def add_jobs(job_descs)
39
40
  job_descs.each do |job_desc|
40
41
  wrapper = Batch.new
41
- wrapper.description = "Pool Job Wrapper"
42
+ wrapper.description = "Pool Job Wrapper (PID: #{pid})"
42
43
  checkin_event = (on_failed_job == :wait) ? :success : :complete
43
44
  wrapper.on(checkin_event, "#{self.class.to_s}.job_checked_in", pool_id: pid)
44
45
  wrapper.jobs {}
@@ -54,24 +55,77 @@ module CanvasSync
54
55
  refill_allotment
55
56
  end
56
57
 
58
+ def keep_open!
59
+ if block_given?
60
+ begin
61
+ keep_open!
62
+ yield
63
+ ensure
64
+ let_close!
65
+ end
66
+ else
67
+ redis do |r|
68
+ r.hset(redis_key, 'keep_open', true)
69
+ end
70
+ end
71
+ end
72
+
73
+ def let_close!
74
+ _, active_count = redis do |r|
75
+ r.multi do
76
+ r.hset(redis_key, 'keep_open', false)
77
+ r.hincrby(redis_key, "active_count", 0)
78
+ end
79
+ end
80
+
81
+ if active_count == 0 && pending_count == 0
82
+ cleanup_redis if clean_when_empty
83
+ end
84
+ end
85
+
57
86
  def cleanup_redis
58
87
  Batch.logger.debug {"Cleaning redis of pool #{pid}"}
59
88
  redis do |r|
60
- r.del(
89
+ r.zrem("pools", pid)
90
+ r.unlink(
61
91
  "#{redis_key}",
62
92
  "#{redis_key}-jobs",
63
93
  )
64
94
  end
65
95
  end
66
96
 
97
+ def active_count
98
+ redis do |r|
99
+ r.hincrby(redis_key, "active_count", 0)
100
+ end
101
+ end
102
+
103
+ def pending_count
104
+ jobs_key = "#{redis_key}-jobs"
105
+ order = self.order || 'fifo'
106
+ redis do |r|
107
+ case order.to_sym
108
+ when :fifo, :lifo
109
+ r.llen(jobs_key)
110
+ when :random
111
+ r.scard(jobs_key)
112
+ when :priority
113
+ r.zcard(jobs_key)
114
+ end
115
+ end
116
+ end
117
+
67
118
  def job_checked_in(status, options)
68
119
  active_count = redis do |r|
120
+ return unless r.exists?(redis_key)
69
121
  r.hincrby(redis_key, "active_count", -1)
70
122
  end
71
- added_count = refill_allotment
72
123
 
124
+ added_count = refill_allotment
73
125
  if active_count == 0 && added_count == 0
74
- cleanup_redis if clean_when_empty
126
+ if clean_when_empty && redis {|r| r.hget(redis_key, 'keep_open') } != 'true'
127
+ cleanup_redis
128
+ end
75
129
  end
76
130
  end
77
131
 
@@ -159,29 +213,25 @@ module CanvasSync
159
213
  ActiveJob::Arguments.deserialize(JSON.parse(job_json))[0]
160
214
  end
161
215
 
162
- def pending_count
163
- order = self.order
164
- redis do |r|
165
- case order.to_sym
166
- when :fifo, :lifo
167
- r.llen(jobs_key)
168
- when :random
169
- r.scard(jobs_key)
170
- when :priority
171
- r.zcard(jobs_key)
172
- end
173
- end
174
- end
175
-
176
216
  def self.redis(&blk)
177
217
  Batch.redis &blk
178
218
  end
179
219
  delegate :redis, to: :class
180
220
 
221
+ protected
222
+
223
+ def flush_pending_attrs
224
+ super
225
+ redis do |r|
226
+ r.zadd("pools", created_at, pid)
227
+ end
228
+ end
229
+
181
230
  private
182
231
 
183
- def initialize_new(concurrency: nil, order: :fifo, clean_when_empty: true, on_failed_job: :wait)
232
+ def initialize_new(concurrency: nil, order: :fifo, clean_when_empty: true, on_failed_job: :wait, description: nil)
184
233
  self.created_at = Time.now.utc.to_f
234
+ self.description = description
185
235
  self.order = order
186
236
  self.concurrency = concurrency
187
237
  self.clean_when_empty = clean_when_empty
@@ -57,16 +57,17 @@ module CanvasSync
57
57
  class ServerMiddleware
58
58
  def call(_worker, msg, _queue)
59
59
  if (bid = msg['bid'])
60
+ prev_batch = Thread.current[:batch]
60
61
  begin
61
62
  Thread.current[:batch] = Batch.new(bid)
62
63
  yield
63
- Thread.current[:batch] = nil
64
+ Thread.current[:batch].save_context_changes
64
65
  Batch.process_successful_job(bid, msg['jid'])
65
66
  rescue
66
67
  Batch.process_failed_job(bid, msg['jid'])
67
68
  raise
68
69
  ensure
69
- Thread.current[:batch] = nil
70
+ Thread.current[:batch] = prev_batch
70
71
  end
71
72
  else
72
73
  yield
@@ -117,3 +118,5 @@ module CanvasSync
117
118
  end
118
119
  end
119
120
  end
121
+
122
+ require_relative 'sidekiq/web'