canvas_sync 0.17.3.beta3 → 0.17.6.beta1
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 +4 -4
- data/lib/canvas_sync/job_batches/batch.rb +79 -14
- data/lib/canvas_sync/job_batches/batch_aware_job.rb +1 -1
- data/lib/canvas_sync/job_batches/callback.rb +16 -16
- data/lib/canvas_sync/job_batches/context_hash.rb +6 -1
- data/lib/canvas_sync/job_batches/pool.rb +69 -19
- data/lib/canvas_sync/job_batches/sidekiq.rb +5 -2
- data/lib/canvas_sync/job_batches/sidekiq/web.rb +114 -0
- data/lib/canvas_sync/job_batches/sidekiq/web/helpers.rb +41 -0
- data/lib/canvas_sync/job_batches/sidekiq/web/views/_batches_table.erb +42 -0
- data/lib/canvas_sync/job_batches/sidekiq/web/views/_pagination.erb +26 -0
- data/lib/canvas_sync/job_batches/sidekiq/web/views/batch.erb +138 -0
- data/lib/canvas_sync/job_batches/sidekiq/web/views/batches.erb +23 -0
- data/lib/canvas_sync/job_batches/sidekiq/web/views/pool.erb +85 -0
- data/lib/canvas_sync/job_batches/sidekiq/web/views/pools.erb +47 -0
- data/lib/canvas_sync/job_batches/status.rb +9 -0
- data/lib/canvas_sync/version.rb +1 -1
- data/spec/dummy/log/test.log +69127 -0
- data/spec/job_batching/batch_spec.rb +28 -1
- data/spec/job_batching/context_hash_spec.rb +54 -0
- data/spec/job_batching/status_spec.rb +3 -3
- data/spec/spec_helper.rb +3 -7
- metadata +12 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ce407ae1dd566665cb8ae02856b61f033001cb25aadb903b5e9261846ad9e0c0
|
4
|
+
data.tar.gz: 349fa1f9e033101be253f2d5e5b8212f243a9ea28d143e683d6b2b6a877fcac6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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",
|
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.
|
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.
|
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
|
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
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
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
|
-
|
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}", "
|
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.
|
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
|
-
|
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]
|
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] =
|
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'
|