canvas_sync 0.17.0.beta15 → 0.17.3.beta2
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/README.md +58 -0
- data/lib/canvas_sync/importers/bulk_importer.rb +7 -4
- data/lib/canvas_sync/job_batches/batch.rb +81 -107
- data/lib/canvas_sync/job_batches/callback.rb +20 -29
- data/lib/canvas_sync/job_batches/context_hash.rb +8 -5
- data/lib/canvas_sync/job_batches/hincr_max.lua +5 -0
- data/lib/canvas_sync/job_batches/jobs/managed_batch_job.rb +99 -0
- data/lib/canvas_sync/job_batches/jobs/serial_batch_job.rb +6 -65
- data/lib/canvas_sync/job_batches/pool.rb +193 -0
- data/lib/canvas_sync/job_batches/redis_model.rb +67 -0
- data/lib/canvas_sync/job_batches/redis_script.rb +163 -0
- data/lib/canvas_sync/job_batches/sidekiq.rb +22 -1
- data/lib/canvas_sync/job_batches/status.rb +0 -5
- data/lib/canvas_sync/jobs/begin_sync_chain_job.rb +4 -2
- data/lib/canvas_sync/jobs/report_starter.rb +1 -0
- data/lib/canvas_sync/processors/assignment_groups_processor.rb +3 -2
- data/lib/canvas_sync/processors/assignments_processor.rb +3 -2
- data/lib/canvas_sync/processors/context_module_items_processor.rb +3 -2
- data/lib/canvas_sync/processors/context_modules_processor.rb +3 -2
- data/lib/canvas_sync/processors/normal_processor.rb +2 -1
- data/lib/canvas_sync/processors/provisioning_report_processor.rb +10 -2
- data/lib/canvas_sync/processors/submissions_processor.rb +3 -2
- data/lib/canvas_sync/version.rb +1 -1
- data/spec/dummy/log/test.log +78907 -0
- data/spec/job_batching/batch_aware_job_spec.rb +1 -0
- data/spec/job_batching/batch_spec.rb +72 -15
- data/spec/job_batching/callback_spec.rb +1 -1
- data/spec/job_batching/flow_spec.rb +5 -11
- data/spec/job_batching/integration/fail_then_succeed.rb +42 -0
- data/spec/job_batching/integration_helper.rb +6 -4
- data/spec/job_batching/sidekiq_spec.rb +1 -0
- data/spec/job_batching/status_spec.rb +1 -17
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 416545a03622711eba78ef420fd07aff9eb1e56ee9536b9e12369406885079c5
|
4
|
+
data.tar.gz: e9cabdc870f0903bcffc60f711c0ed34a5b471d1bbdf1d8a2a4d83ce9ac745a4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 020ba0e260823c40a21273c3bda767c9774207fa36bf7e639d0927db19d544a27b1fefcebfdd64e2b4445ba5ca526098229d95e4c3ee7f5f6e336ef42da8a1f6
|
7
|
+
data.tar.gz: 1840797de37257526d002507fe1849c84cd5cc71ed5bbb176a93061dce8d4c25e85528ec7312a3215e9520bcf4f708ac8cf5834539fdac4a7810919700844d33
|
data/README.md
CHANGED
@@ -246,6 +246,64 @@ A batch can be created using `Sidekiq::Batch` or `CanvasSync::JobBatching::Batch
|
|
246
246
|
|
247
247
|
Also see `canvas_sync/jobs/begin_sync_chain_job`, `canvas_sync/Job_batches/jobs/serial_batch_job`, or `canvas_sync/Job_batches/jobs/concurrent_batch_job` for example usage.
|
248
248
|
|
249
|
+
Example:
|
250
|
+
```ruby
|
251
|
+
batch = CanvasSync::JobBatches::Batch.new
|
252
|
+
batch.description = "Some Batch" # Optional, but can be useful for debugging
|
253
|
+
|
254
|
+
batch.on(:complete, "SomeClass.on_complete", kw_param: 1)
|
255
|
+
batch.on(:success, "SomeClass.on_success", some_param: 'foo')
|
256
|
+
|
257
|
+
# Add context to the batch. Can be accessed as batch_context on any jobs within the batch.
|
258
|
+
# Nested Batches will have their contexts merged
|
259
|
+
batch.context = {
|
260
|
+
some_value: 'blah',
|
261
|
+
}
|
262
|
+
|
263
|
+
batch.jobs do
|
264
|
+
# Enqueue jobs like normal
|
265
|
+
end
|
266
|
+
```
|
267
|
+
|
268
|
+
#### Job Pools
|
269
|
+
A job pool is like a custom Sidekiq Queue. You can add jobs to it and it will empty itself out into one of the actual queues.
|
270
|
+
However, it adds some options for tweaking the logic:
|
271
|
+
- `concurrency` (default: `nil`) - Define how many jobs from the pool can run at once.
|
272
|
+
- `order` (default: `fifo`) - Define how the pool will empty itself
|
273
|
+
- `fifo` - First-In First-Out, a traditional queue
|
274
|
+
- `lifo` - Last-In First-Out
|
275
|
+
- `random` - Pluck and run jobs in random order
|
276
|
+
- `priority` - Execute jobs in a priority order (NB: Due to Redis, this priority-random, meaning that items with the same priority will be run in random order, not fifo)
|
277
|
+
- `clean_when_empty` (default: `true`) - Automatically clean the pool when it is empty
|
278
|
+
- `on_failed_job` (default `:wait`) - If a Job fails, should the pool `:continue` and still enqueue the next job or `:wait` for the job to succeed
|
279
|
+
|
280
|
+
Example:
|
281
|
+
```ruby
|
282
|
+
pool = CanvasSync::JobBatches::Pool.new(concurrency: 4, order: :priority, clean_when_empty: false)
|
283
|
+
pool_id = pool.pid
|
284
|
+
|
285
|
+
# Add a job to the pool
|
286
|
+
pool << {
|
287
|
+
job: SomeJob, # The Class of a ActiveJob Job or Sidekiq Worker
|
288
|
+
parameters: [1, 2, 3], # Array of params to pass th e Job
|
289
|
+
priority: 100, # Only effective if order=:priority, higher is higher
|
290
|
+
}
|
291
|
+
|
292
|
+
# Add many jobs to the pool
|
293
|
+
pool.add_jobs([
|
294
|
+
{
|
295
|
+
job: SomeJob, # The Class of a ActiveJob Job or Sidekiq Worker
|
296
|
+
parameters: [1, 2, 3], # Array of params to pass th e Job
|
297
|
+
priority: 100, # Only effective if order=:priority, higher is higher
|
298
|
+
},
|
299
|
+
# ...
|
300
|
+
])
|
301
|
+
|
302
|
+
# ...Later
|
303
|
+
CanvasSync::JobBatches::Pool.from_pid(pool_id).cleanup_redis
|
304
|
+
|
305
|
+
```
|
306
|
+
|
249
307
|
## Legacy Support
|
250
308
|
|
251
309
|
### Legacy Mappings
|
@@ -64,13 +64,12 @@ module CanvasSync
|
|
64
64
|
columns = columns.dup
|
65
65
|
|
66
66
|
update_conditions = {
|
67
|
-
condition: condition_sql(klass, columns),
|
67
|
+
condition: condition_sql(klass, columns, import_args[:sync_start_time]),
|
68
68
|
columns: columns
|
69
69
|
}
|
70
70
|
update_conditions[:conflict_target] = conflict_target if conflict_target
|
71
71
|
|
72
72
|
options = { validate: false, on_duplicate_key_update: update_conditions }.merge(import_args)
|
73
|
-
|
74
73
|
options.delete(:on_duplicate_key_update) if options.key?(:on_duplicate_key_ignore)
|
75
74
|
klass.import(columns, rows, options)
|
76
75
|
end
|
@@ -85,10 +84,14 @@ module CanvasSync
|
|
85
84
|
# started_at = Time.now
|
86
85
|
# run_the_users_sync!
|
87
86
|
# changed = User.where("updated_at >= ?", started_at)
|
88
|
-
def self.condition_sql(klass, columns)
|
87
|
+
def self.condition_sql(klass, columns, report_start)
|
89
88
|
columns_str = columns.map { |c| "#{klass.quoted_table_name}.#{c}" }.join(", ")
|
90
89
|
excluded_str = columns.map { |c| "EXCLUDED.#{c}" }.join(", ")
|
91
|
-
"(#{columns_str}) IS DISTINCT FROM (#{excluded_str})"
|
90
|
+
condition_sql = "(#{columns_str}) IS DISTINCT FROM (#{excluded_str})"
|
91
|
+
if klass.column_names.include?("updated_at") && report_start
|
92
|
+
condition_sql += " AND #{klass.quoted_table_name}.updated_at < '#{report_start}'"
|
93
|
+
end
|
94
|
+
condition_sql
|
92
95
|
end
|
93
96
|
|
94
97
|
def self.batch_size
|
@@ -4,10 +4,13 @@ begin
|
|
4
4
|
rescue LoadError
|
5
5
|
end
|
6
6
|
|
7
|
+
require_relative './redis_model'
|
8
|
+
require_relative './redis_script'
|
7
9
|
require_relative './batch_aware_job'
|
8
10
|
require_relative "./callback"
|
9
11
|
require_relative "./context_hash"
|
10
12
|
require_relative "./status"
|
13
|
+
require_relative "./pool"
|
11
14
|
Dir[File.dirname(__FILE__) + "/jobs/*.rb"].each { |file| require file }
|
12
15
|
require_relative "./chain_builder"
|
13
16
|
|
@@ -17,24 +20,9 @@ require_relative "./chain_builder"
|
|
17
20
|
module CanvasSync
|
18
21
|
module JobBatches
|
19
22
|
class Batch
|
20
|
-
|
21
|
-
|
22
|
-
def self.batch_attr(key, read_only: true)
|
23
|
-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
24
|
-
def #{key}=(value)
|
25
|
-
raise "#{key} is read-only once the batch has been started" if #{read_only.to_s} && (@initialized || @existing)
|
26
|
-
@#{key} = value
|
27
|
-
persist_bid_attr('#{key}', value)
|
28
|
-
end
|
23
|
+
include RedisModel
|
29
24
|
|
30
|
-
|
31
|
-
return @#{key} if defined?(@#{key})
|
32
|
-
if (@initialized || @existing)
|
33
|
-
@#{key} = read_bid_attr('#{key}')
|
34
|
-
end
|
35
|
-
end
|
36
|
-
RUBY
|
37
|
-
end
|
25
|
+
class NoBlockGivenError < StandardError; end
|
38
26
|
|
39
27
|
delegate :redis, to: :class
|
40
28
|
|
@@ -47,16 +35,14 @@ module CanvasSync
|
|
47
35
|
@existing = !(!existing_bid || existing_bid.empty?) # Basically existing_bid.present?
|
48
36
|
@initialized = false
|
49
37
|
@bidkey = "BID-" + @bid.to_s
|
50
|
-
@pending_attrs = {}
|
51
|
-
@ready_to_queue = nil
|
52
38
|
self.created_at = Time.now.utc.to_f unless @existing
|
53
39
|
end
|
54
40
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
41
|
+
redis_attr :description
|
42
|
+
redis_attr :created_at
|
43
|
+
redis_attr :callback_queue, read_only: false
|
44
|
+
redis_attr :callback_params, :json
|
45
|
+
redis_attr :allow_context_changes
|
60
46
|
|
61
47
|
def context
|
62
48
|
return @context if defined?(@context)
|
@@ -122,29 +108,24 @@ module CanvasSync
|
|
122
108
|
@context&.save!
|
123
109
|
|
124
110
|
@initialized = true
|
111
|
+
else
|
112
|
+
assert_batch_is_open
|
125
113
|
end
|
126
114
|
|
127
|
-
job_queue = @ready_to_queue = []
|
128
|
-
|
129
115
|
begin
|
130
116
|
parent = Thread.current[:batch]
|
131
117
|
Thread.current[:batch] = self
|
132
118
|
yield
|
133
119
|
ensure
|
134
|
-
@ready_to_queue = nil
|
135
|
-
append_jobs(job_queue, parent_bid)
|
136
120
|
Thread.current[:batch] = parent
|
137
121
|
end
|
138
122
|
|
139
|
-
|
123
|
+
nil
|
140
124
|
end
|
141
125
|
|
142
126
|
def increment_job_queue(jid)
|
143
|
-
|
144
|
-
|
145
|
-
else
|
146
|
-
append_jobs([jid])
|
147
|
-
end
|
127
|
+
assert_batch_is_open
|
128
|
+
append_jobs([jid])
|
148
129
|
end
|
149
130
|
|
150
131
|
def invalidate_all
|
@@ -170,52 +151,42 @@ module CanvasSync
|
|
170
151
|
batch.parent ? valid && valid?(batch.parent) : valid
|
171
152
|
end
|
172
153
|
|
173
|
-
|
174
|
-
|
154
|
+
def self.with_batch(batch)
|
155
|
+
batch = self.new(batch) if batch.is_a?(String)
|
175
156
|
parent = Thread.current[:batch]
|
176
|
-
Thread.current[:batch] =
|
157
|
+
Thread.current[:batch] = batch
|
177
158
|
yield
|
178
159
|
ensure
|
179
160
|
Thread.current[:batch] = parent
|
180
161
|
end
|
181
162
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
if @initialized || @existing
|
186
|
-
redis do |r|
|
187
|
-
r.multi do
|
188
|
-
r.hset(@bidkey, attribute, value)
|
189
|
-
r.expire(@bidkey, BID_EXPIRE_TTL)
|
190
|
-
end
|
191
|
-
end
|
192
|
-
else
|
193
|
-
@pending_attrs[attribute] = value
|
194
|
-
end
|
163
|
+
# Any Batches or Jobs created in the given block won't be assocaiated to the current batch
|
164
|
+
def self.without_batch(&blk)
|
165
|
+
with_batch(nil, &blk)
|
195
166
|
end
|
196
167
|
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
168
|
+
protected
|
169
|
+
|
170
|
+
def redis_key
|
171
|
+
@bidkey
|
201
172
|
end
|
202
173
|
|
203
|
-
|
204
|
-
|
205
|
-
|
174
|
+
private
|
175
|
+
|
176
|
+
def assert_batch_is_open
|
177
|
+
unless defined?(@closed)
|
178
|
+
redis do |r|
|
179
|
+
@closed = r.hget(@bidkey, 'closed') == 'true'
|
180
|
+
end
|
206
181
|
end
|
207
|
-
|
182
|
+
raise "Cannot add jobs to Batch #{} bid - it has already entered the callback-stage" if @closed
|
208
183
|
end
|
209
184
|
|
210
|
-
def append_jobs(jids
|
185
|
+
def append_jobs(jids)
|
186
|
+
jids = jids.uniq
|
211
187
|
redis do |r|
|
212
188
|
r.multi do
|
213
|
-
if parent_bid
|
214
|
-
r.hincrby("BID-#{parent_bid}", "total", jids.size)
|
215
|
-
end
|
216
|
-
|
217
189
|
r.hincrby(@bidkey, "pending", jids.size)
|
218
|
-
r.hincrby(@bidkey, "total", jids.size)
|
219
190
|
r.expire(@bidkey, BID_EXPIRE_TTL)
|
220
191
|
|
221
192
|
if jids.size > 0
|
@@ -242,17 +213,6 @@ module CanvasSync
|
|
242
213
|
end
|
243
214
|
end
|
244
215
|
|
245
|
-
# if the batch failed, and has a parent, update the parent to show one pending and failed job
|
246
|
-
if parent_bid
|
247
|
-
redis do |r|
|
248
|
-
r.multi do
|
249
|
-
r.hincrby("BID-#{parent_bid}", "pending", 1)
|
250
|
-
r.sadd("BID-#{parent_bid}-failed", jid)
|
251
|
-
r.expire("BID-#{parent_bid}-failed", BID_EXPIRE_TTL)
|
252
|
-
end
|
253
|
-
end
|
254
|
-
end
|
255
|
-
|
256
216
|
if pending.to_i == failed.to_i && children == complete
|
257
217
|
enqueue_callbacks(:complete, bid)
|
258
218
|
end
|
@@ -285,7 +245,7 @@ module CanvasSync
|
|
285
245
|
end
|
286
246
|
|
287
247
|
def process_successful_job(bid, jid)
|
288
|
-
_, failed, pending, children, complete, success,
|
248
|
+
_, failed, pending, children, complete, success, parent_bid = redis do |r|
|
289
249
|
r.multi do
|
290
250
|
r.srem("BID-#{bid}-failed", jid)
|
291
251
|
|
@@ -294,7 +254,6 @@ module CanvasSync
|
|
294
254
|
r.hincrby("BID-#{bid}", "children", 0)
|
295
255
|
r.scard("BID-#{bid}-batches-complete")
|
296
256
|
r.scard("BID-#{bid}-batches-success")
|
297
|
-
r.hget("BID-#{bid}", "total")
|
298
257
|
r.hget("BID-#{bid}", "parent_bid")
|
299
258
|
|
300
259
|
r.srem("BID-#{bid}-jids", jid)
|
@@ -302,6 +261,8 @@ module CanvasSync
|
|
302
261
|
end
|
303
262
|
end
|
304
263
|
|
264
|
+
# TODO - There seems to be an issue where a :complete callback batch will occasionally run its job, but won't enqueue_callbacks()
|
265
|
+
|
305
266
|
all_success = pending.to_i.zero? && children == success
|
306
267
|
# if complete or successfull call complete callback (the complete callback may then call successful)
|
307
268
|
if (pending.to_i == failed.to_i && children == complete) || all_success
|
@@ -310,17 +271,34 @@ module CanvasSync
|
|
310
271
|
end
|
311
272
|
end
|
312
273
|
|
274
|
+
def possibly_enqueue_callbacks(bid, types: [:complete, :success])
|
275
|
+
pending_jobs, failed_jobs, total_batches, completed_batches, successful_batches = redis do |r|
|
276
|
+
r.multi do
|
277
|
+
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
if (types.include?(:complete)) && (pending_jobs.to_i == failed_jobs.to_i && total_batches.to_i == completed_batches.to_i)
|
282
|
+
enqueue_callbacks(:complete, bid)
|
283
|
+
end
|
284
|
+
if (types.include?(:success)) && (pending_jobs.to_i.zero? && total_batches.to_i == successful_batches.to_i)
|
285
|
+
enqueue_callbacks(:success, bid)
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
313
289
|
def enqueue_callbacks(event, bid)
|
314
290
|
batch_key = "BID-#{bid}"
|
315
291
|
callback_key = "#{batch_key}-callbacks-#{event}"
|
316
|
-
already_processed, _, callbacks, queue, parent_bid,
|
292
|
+
already_processed, _, _, callbacks, queue, parent_bid, callback_params = redis do |r|
|
293
|
+
return unless r.exists?(batch_key)
|
317
294
|
r.multi do
|
318
295
|
r.hget(batch_key, event)
|
296
|
+
r.hset(batch_key, "closed", true)
|
319
297
|
r.hset(batch_key, event, true)
|
320
298
|
r.smembers(callback_key)
|
321
299
|
r.hget(batch_key, "callback_queue")
|
322
300
|
r.hget(batch_key, "parent_bid")
|
323
|
-
r.hget(batch_key, "
|
301
|
+
r.hget(batch_key, "callback_params")
|
324
302
|
end
|
325
303
|
end
|
326
304
|
|
@@ -328,6 +306,7 @@ module CanvasSync
|
|
328
306
|
|
329
307
|
queue ||= "default"
|
330
308
|
parent_bid = !parent_bid || parent_bid.empty? ? nil : parent_bid # Basically parent_bid.blank?
|
309
|
+
callback_params = JSON.parse(callback_params) if callback_params.present?
|
331
310
|
callback_args = callbacks.reduce([]) do |memo, jcb|
|
332
311
|
cb = JSON.load(jcb)
|
333
312
|
memo << [cb['callback'], event.to_s, cb['opts'], bid, parent_bid]
|
@@ -335,38 +314,32 @@ module CanvasSync
|
|
335
314
|
|
336
315
|
opts = {"bid" => bid, "event" => event}
|
337
316
|
|
338
|
-
|
339
|
-
|
340
|
-
# Extract opts from cb_args or use current
|
341
|
-
# Pass in stored event as callback finalize is processed on complete event
|
342
|
-
cb_opts = callback_args.first&.at(2) || opts
|
317
|
+
if callback_args.present? && !callback_params.present?
|
318
|
+
logger.debug {"Enqueue callback bid: #{bid} event: #{event} args: #{callback_args.inspect}"}
|
343
319
|
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
320
|
+
with_batch(parent_bid) do
|
321
|
+
cb_batch = self.new
|
322
|
+
cb_batch.callback_params = {
|
323
|
+
for_bid: bid,
|
324
|
+
event: event,
|
325
|
+
}
|
326
|
+
opts['callback_bid'] = cb_batch.bid
|
349
327
|
|
350
|
-
|
328
|
+
logger.debug {"Adding callback batch: #{cb_batch.bid} for batch: #{bid}"}
|
329
|
+
cb_batch.jobs do
|
330
|
+
push_callbacks callback_args, queue
|
331
|
+
end
|
332
|
+
end
|
351
333
|
end
|
352
334
|
|
353
|
-
|
354
|
-
|
355
|
-
if callback_args.empty?
|
356
|
-
# Finalize now
|
357
|
-
finalizer = Batch::Callback::Finalize.new
|
358
|
-
status = Status.new bid
|
359
|
-
finalizer.dispatch(status, opts)
|
360
|
-
else
|
361
|
-
# Otherwise finalize in sub batch complete callback
|
362
|
-
cb_batch = self.new
|
363
|
-
cb_batch.callback_batch = true
|
364
|
-
logger.debug {"Adding callback batch: #{cb_batch.bid} for batch: #{bid}"}
|
365
|
-
cb_batch.on(:complete, "#{Batch::Callback::Finalize.to_s}#dispatch", opts)
|
366
|
-
cb_batch.jobs do
|
367
|
-
push_callbacks callback_args, queue
|
368
|
-
end
|
335
|
+
if callback_params.present?
|
336
|
+
opts['origin'] = callback_params
|
369
337
|
end
|
338
|
+
|
339
|
+
logger.debug {"Run batch finalizer bid: #{bid} event: #{event} args: #{callback_args.inspect}"}
|
340
|
+
finalizer = Batch::Callback::Finalize.new
|
341
|
+
status = Status.new bid
|
342
|
+
finalizer.dispatch(status, opts)
|
370
343
|
end
|
371
344
|
|
372
345
|
def cleanup_redis(bid)
|
@@ -381,6 +354,7 @@ module CanvasSync
|
|
381
354
|
"BID-#{bid}-batches-success",
|
382
355
|
"BID-#{bid}-batches-complete",
|
383
356
|
"BID-#{bid}-batches-failed",
|
357
|
+
"BID-#{bid}-bids",
|
384
358
|
"BID-#{bid}-jids",
|
385
359
|
)
|
386
360
|
end
|
@@ -397,7 +371,7 @@ module CanvasSync
|
|
397
371
|
private
|
398
372
|
|
399
373
|
def push_callbacks(args, queue)
|
400
|
-
Batch::Callback::
|
374
|
+
Batch::Callback::worker_class.enqueue_all(args, queue)
|
401
375
|
end
|
402
376
|
end
|
403
377
|
end
|
@@ -2,6 +2,7 @@ module CanvasSync
|
|
2
2
|
module JobBatches
|
3
3
|
class Batch
|
4
4
|
module Callback
|
5
|
+
mattr_accessor :worker_class
|
5
6
|
|
6
7
|
VALID_CALLBACKS = %w[success complete dead].freeze
|
7
8
|
|
@@ -47,41 +48,28 @@ module CanvasSync
|
|
47
48
|
end
|
48
49
|
end
|
49
50
|
|
50
|
-
|
51
|
-
class SidekiqCallbackWorker
|
52
|
-
include ::Sidekiq::Worker
|
53
|
-
include CallbackWorkerCommon
|
54
|
-
|
55
|
-
def self.enqueue_all(args, queue)
|
56
|
-
return if args.empty?
|
57
|
-
|
58
|
-
::Sidekiq::Client.push_bulk(
|
59
|
-
'class' => self,
|
60
|
-
'args' => args,
|
61
|
-
'queue' => queue
|
62
|
-
)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
Worker = SidekiqCallbackWorker
|
66
|
-
else
|
67
|
-
Worker = ActiveJobCallbackWorker
|
68
|
-
end
|
51
|
+
worker_class = ActiveJobCallbackWorker
|
69
52
|
|
70
53
|
class Finalize
|
71
|
-
def dispatch
|
54
|
+
def dispatch(status, opts)
|
55
|
+
is_callback_batch = opts['origin'].present?
|
56
|
+
has_callback_batch = opts['callback_bid'].present?
|
57
|
+
|
72
58
|
bid = opts["bid"]
|
73
|
-
callback_bid = status.bid
|
74
59
|
event = opts["event"].to_sym
|
75
|
-
callback_batch = bid != callback_bid
|
76
60
|
|
77
|
-
Batch.logger.debug {"Finalize #{event} batch id: #{opts["bid"]}, callback batch id: #{callback_bid} callback_batch #{
|
61
|
+
Batch.logger.debug {"Finalize #{event} batch id: #{opts["bid"]}, callback batch id: #{callback_bid} callback_batch #{is_callback_batch}"}
|
78
62
|
|
79
63
|
batch_status = Status.new bid
|
80
64
|
send(event, bid, batch_status, batch_status.parent_bid)
|
81
65
|
|
82
|
-
|
83
|
-
|
84
|
-
|
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'])
|
72
|
+
end
|
85
73
|
end
|
86
74
|
|
87
75
|
def success(bid, status, parent_bid)
|
@@ -102,8 +90,9 @@ module CanvasSync
|
|
102
90
|
r.scard("BID-#{parent_bid}-failed")
|
103
91
|
end
|
104
92
|
end
|
105
|
-
|
106
|
-
#
|
93
|
+
|
94
|
+
# If the job finished successfully and parent batch is completed, call parent :complete callback
|
95
|
+
# Parent :success callback will be called by its :complete callback
|
107
96
|
if complete == children && pending == failure
|
108
97
|
Batch.logger.debug {"Finalize parent complete bid: #{parent_bid}"}
|
109
98
|
Batch.enqueue_callbacks(:complete, parent_bid)
|
@@ -119,10 +108,12 @@ module CanvasSync
|
|
119
108
|
end
|
120
109
|
end
|
121
110
|
|
122
|
-
#
|
111
|
+
# If the batch was successful run :success callback, which will call the parent's :complete callback (if necessary)
|
112
|
+
# Also, only trigger the success callback if the :complete callback_batch was successful
|
123
113
|
if pending.to_i.zero? && children == success
|
124
114
|
Batch.enqueue_callbacks(:success, bid)
|
125
115
|
|
116
|
+
# otherwise check for a parent and call its :complete if needed
|
126
117
|
elsif parent_bid
|
127
118
|
# if batch was not successfull check and see if its parent is complete
|
128
119
|
# if the parent is complete we trigger the complete callback
|