canvas_sync 0.17.23.beta7 → 0.17.26.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/canvas_sync/job_batches/batch.rb +99 -58
- data/lib/canvas_sync/job_batches/batch_aware_job.rb +7 -7
- data/lib/canvas_sync/job_batches/chain_builder.rb +39 -6
- data/lib/canvas_sync/job_batches/pool.rb +42 -52
- data/lib/canvas_sync/job_batches/sidekiq.rb +7 -7
- data/lib/canvas_sync/jobs/begin_sync_chain_job.rb +9 -1
- data/lib/canvas_sync/jobs/sync_terms_job.rb +1 -17
- data/lib/canvas_sync/jobs/term_batches_job.rb +23 -0
- data/lib/canvas_sync/version.rb +1 -1
- data/lib/canvas_sync.rb +21 -8
- data/spec/canvas_sync/processors/provisioning_report_processor_spec.rb +8 -1
- data/spec/dummy/log/development.log +540 -0
- data/spec/dummy/log/test.log +65350 -0
- data/spec/job_batching/batch_aware_job_spec.rb +3 -3
- data/spec/job_batching/batch_spec.rb +40 -1
- data/spec/job_batching/sidekiq_spec.rb +2 -2
- data/spec/support/fixtures/reports/xlist.csv +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ce544260a5cc94f9193cb99da3bc55e06ecd1078e0ef6a5afca282cc4d39169f
|
4
|
+
data.tar.gz: 30a5bccedebde1cb00aeb31219b1d9f605672fa8ea58cb50af483cf8f98d15fb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e84bde52492c2276650bd662adff677c0aa6a1c511587886d45fc6d328389af242ade72fe872dda2093df9ebb151aa25a4a353559a31d74330849f0a0c93d159
|
7
|
+
data.tar.gz: 3c30eceedad806932b61abc66456973250c7247ba7431406f1c5440b09b05cc3b7174112e34e78392d8f3e9c89dfcd7eba43377a0f8ee30d6320a00a50303163
|
@@ -19,6 +19,8 @@ require_relative "./chain_builder"
|
|
19
19
|
|
20
20
|
module CanvasSync
|
21
21
|
module JobBatches
|
22
|
+
CURRENT_BATCH_THREAD_KEY = :job_batches_batch
|
23
|
+
|
22
24
|
class Batch
|
23
25
|
include RedisModel
|
24
26
|
|
@@ -76,14 +78,12 @@ module CanvasSync
|
|
76
78
|
def on(event, callback, options = {})
|
77
79
|
return unless Callback::VALID_CALLBACKS.include?(event.to_s)
|
78
80
|
callback_key = "#{@bidkey}-callbacks-#{event}"
|
79
|
-
redis do |r|
|
80
|
-
r.
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
r.expire(callback_key, BID_EXPIRE_TTL)
|
86
|
-
end
|
81
|
+
redis.multi do |r|
|
82
|
+
r.sadd(callback_key, JSON.unparse({
|
83
|
+
callback: callback,
|
84
|
+
opts: options
|
85
|
+
}))
|
86
|
+
r.expire(callback_key, BID_EXPIRE_TTL)
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
@@ -91,18 +91,16 @@ module CanvasSync
|
|
91
91
|
raise NoBlockGivenError unless block_given?
|
92
92
|
|
93
93
|
if !@existing && !@initialized
|
94
|
-
parent_bid = Thread.current[
|
94
|
+
parent_bid = Thread.current[CURRENT_BATCH_THREAD_KEY]&.bid
|
95
95
|
|
96
|
-
redis do |r|
|
97
|
-
r.
|
98
|
-
|
99
|
-
r.expire(@bidkey, BID_EXPIRE_TTL)
|
96
|
+
redis.multi do |r|
|
97
|
+
r.hset(@bidkey, "parent_bid", parent_bid.to_s) if parent_bid
|
98
|
+
r.expire(@bidkey, BID_EXPIRE_TTL)
|
100
99
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
end
|
100
|
+
if parent_bid
|
101
|
+
r.hincrby("BID-#{parent_bid}", "children", 1)
|
102
|
+
r.expire("BID-#{parent_bid}", BID_EXPIRE_TTL)
|
103
|
+
r.zadd("BID-#{parent_bid}-bids", created_at, bid)
|
106
104
|
end
|
107
105
|
end
|
108
106
|
|
@@ -115,11 +113,11 @@ module CanvasSync
|
|
115
113
|
end
|
116
114
|
|
117
115
|
begin
|
118
|
-
parent = Thread.current[
|
119
|
-
Thread.current[
|
116
|
+
parent = Thread.current[CURRENT_BATCH_THREAD_KEY]
|
117
|
+
Thread.current[CURRENT_BATCH_THREAD_KEY] = self
|
120
118
|
yield
|
121
119
|
ensure
|
122
|
-
Thread.current[
|
120
|
+
Thread.current[CURRENT_BATCH_THREAD_KEY] = parent
|
123
121
|
end
|
124
122
|
|
125
123
|
nil
|
@@ -131,15 +129,11 @@ module CanvasSync
|
|
131
129
|
end
|
132
130
|
|
133
131
|
def invalidate_all
|
134
|
-
redis
|
135
|
-
r.setex("invalidated-bid-#{bid}", BID_EXPIRE_TTL, 1)
|
136
|
-
end
|
132
|
+
redis.setex("invalidated-bid-#{bid}", BID_EXPIRE_TTL, 1)
|
137
133
|
end
|
138
134
|
|
139
135
|
def parent_bid
|
140
|
-
redis
|
141
|
-
r.hget(@bidkey, "parent_bid")
|
142
|
-
end
|
136
|
+
redis.hget(@bidkey, "parent_bid")
|
143
137
|
end
|
144
138
|
|
145
139
|
def parent
|
@@ -149,7 +143,7 @@ module CanvasSync
|
|
149
143
|
end
|
150
144
|
|
151
145
|
def valid?(batch = self)
|
152
|
-
valid = !redis
|
146
|
+
valid = !redis.exists?("invalidated-bid-#{batch.bid}")
|
153
147
|
batch.parent ? valid && valid?(batch.parent) : valid
|
154
148
|
end
|
155
149
|
|
@@ -162,23 +156,19 @@ module CanvasSync
|
|
162
156
|
let_close!
|
163
157
|
end
|
164
158
|
else
|
165
|
-
redis
|
166
|
-
r.hset(@bidkey, 'keep_open', true)
|
167
|
-
end
|
159
|
+
redis.hset(@bidkey, 'keep_open', true)
|
168
160
|
end
|
169
161
|
end
|
170
162
|
|
171
163
|
def let_close!
|
172
|
-
_, failed, pending, children, complete, success = redis do |r|
|
173
|
-
r.
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
r.scard("BID-#{bid}-batches-success")
|
181
|
-
end
|
164
|
+
_, failed, pending, children, complete, success = redis.multi do |r|
|
165
|
+
r.hset(@bidkey, 'keep_open', false)
|
166
|
+
|
167
|
+
r.scard("BID-#{bid}-failed")
|
168
|
+
r.hincrby("BID-#{bid}", "pending", 0)
|
169
|
+
r.hincrby("BID-#{bid}", "children", 0)
|
170
|
+
r.scard("BID-#{bid}-batches-complete")
|
171
|
+
r.scard("BID-#{bid}-batches-success")
|
182
172
|
end
|
183
173
|
|
184
174
|
all_success = pending.to_i.zero? && children == success
|
@@ -191,11 +181,11 @@ module CanvasSync
|
|
191
181
|
|
192
182
|
def self.with_batch(batch)
|
193
183
|
batch = self.new(batch) if batch.is_a?(String)
|
194
|
-
parent = Thread.current[
|
195
|
-
Thread.current[
|
184
|
+
parent = Thread.current[CURRENT_BATCH_THREAD_KEY]
|
185
|
+
Thread.current[CURRENT_BATCH_THREAD_KEY] = batch
|
196
186
|
yield
|
197
187
|
ensure
|
198
|
-
Thread.current[
|
188
|
+
Thread.current[CURRENT_BATCH_THREAD_KEY] = parent
|
199
189
|
end
|
200
190
|
|
201
191
|
# Any Batches or Jobs created in the given block won't be assocaiated to the current batch
|
@@ -211,18 +201,14 @@ module CanvasSync
|
|
211
201
|
|
212
202
|
def flush_pending_attrs
|
213
203
|
super
|
214
|
-
redis
|
215
|
-
r.zadd("batches", created_at, bid)
|
216
|
-
end
|
204
|
+
redis.zadd("batches", created_at, bid)
|
217
205
|
end
|
218
206
|
|
219
207
|
private
|
220
208
|
|
221
209
|
def assert_batch_is_open
|
222
210
|
unless defined?(@closed)
|
223
|
-
redis
|
224
|
-
@closed = r.hget(@bidkey, 'success') == 'true'
|
225
|
-
end
|
211
|
+
@closed = redis.hget(@bidkey, 'success') == 'true'
|
226
212
|
end
|
227
213
|
raise "Cannot add jobs to Batch #{} bid - it has already entered the callback-stage" if @closed
|
228
214
|
end
|
@@ -234,7 +220,7 @@ module CanvasSync
|
|
234
220
|
redis do |r|
|
235
221
|
tme = Time.now.utc.to_f
|
236
222
|
added = r.zadd(@bidkey + "-jids", jids.map{|jid| [tme, jid] }, nx: true)
|
237
|
-
r.multi do
|
223
|
+
r.multi do |r|
|
238
224
|
r.hincrby(@bidkey, "pending", added)
|
239
225
|
r.hincrby(@bidkey, "job_count", added)
|
240
226
|
r.expire(@bidkey, BID_EXPIRE_TTL)
|
@@ -244,6 +230,14 @@ module CanvasSync
|
|
244
230
|
end
|
245
231
|
|
246
232
|
class << self
|
233
|
+
def current
|
234
|
+
Thread.current[CURRENT_BATCH_THREAD_KEY]
|
235
|
+
end
|
236
|
+
|
237
|
+
def current_context
|
238
|
+
current&.context || {}
|
239
|
+
end
|
240
|
+
|
247
241
|
def process_failed_job(bid, jid)
|
248
242
|
_, pending, failed, children, complete, parent_bid = redis do |r|
|
249
243
|
return unless r.exists?("BID-#{bid}")
|
@@ -283,11 +277,9 @@ module CanvasSync
|
|
283
277
|
end
|
284
278
|
|
285
279
|
if parent_bid
|
286
|
-
redis do
|
287
|
-
r.
|
288
|
-
|
289
|
-
r.expire("BID-#{parent_bid}-dead", BID_EXPIRE_TTL)
|
290
|
-
end
|
280
|
+
redis.multi do
|
281
|
+
r.sadd("BID-#{parent_bid}-dead", jid)
|
282
|
+
r.expire("BID-#{parent_bid}-dead", BID_EXPIRE_TTL)
|
291
283
|
end
|
292
284
|
end
|
293
285
|
|
@@ -413,8 +405,21 @@ module CanvasSync
|
|
413
405
|
cleanup_redis(bid)
|
414
406
|
end
|
415
407
|
|
416
|
-
def redis(
|
417
|
-
|
408
|
+
def redis(&blk)
|
409
|
+
return RedisProxy.new unless block_given?
|
410
|
+
|
411
|
+
if Thread.current[:job_batches_redis]
|
412
|
+
yield Thread.current[:job_batches_redis]
|
413
|
+
elsif defined?(::Sidekiq)
|
414
|
+
::Sidekiq.redis do |r|
|
415
|
+
Thread.current[:job_batches_redis] = r
|
416
|
+
yield r
|
417
|
+
ensure
|
418
|
+
Thread.current[:job_batches_redis] = nil
|
419
|
+
end
|
420
|
+
else
|
421
|
+
# TODO
|
422
|
+
end
|
418
423
|
end
|
419
424
|
|
420
425
|
def logger
|
@@ -433,6 +438,42 @@ module CanvasSync
|
|
433
438
|
end
|
434
439
|
end
|
435
440
|
end
|
441
|
+
|
442
|
+
class RedisProxy
|
443
|
+
def multi(*args, &block)
|
444
|
+
Batch.redis do |r|
|
445
|
+
if block.arity == 1
|
446
|
+
r.multi(*args) do
|
447
|
+
block.call(r)
|
448
|
+
end
|
449
|
+
else
|
450
|
+
r.multi(*args, &block)
|
451
|
+
end
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
455
|
+
def pipelined(*args, &block)
|
456
|
+
Batch.redis do |r|
|
457
|
+
if block.arity == 1
|
458
|
+
r.pipelined(*args) do
|
459
|
+
block.call(r)
|
460
|
+
end
|
461
|
+
else
|
462
|
+
r.pipelined(*args, &block)
|
463
|
+
end
|
464
|
+
end
|
465
|
+
end
|
466
|
+
|
467
|
+
def method_missing(method_name, *arguments, &block)
|
468
|
+
Batch.redis do |r|
|
469
|
+
r.send(method_name, *arguments, &block)
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
def respond_to_missing?(method_name, include_private = false)
|
474
|
+
super || Redis.method_defined?(method_name)
|
475
|
+
end
|
476
|
+
end
|
436
477
|
end
|
437
478
|
|
438
479
|
ActiveJob::Base.include BatchAwareJob
|
@@ -6,17 +6,17 @@ module CanvasSync
|
|
6
6
|
included do
|
7
7
|
around_perform do |job, block|
|
8
8
|
if (@bid) # This _must_ be @bid - not just bid
|
9
|
-
prev_batch = Thread.current[
|
9
|
+
prev_batch = Thread.current[CURRENT_BATCH_THREAD_KEY]
|
10
10
|
begin
|
11
|
-
Thread.current[
|
11
|
+
Thread.current[CURRENT_BATCH_THREAD_KEY] = Batch.new(@bid)
|
12
12
|
block.call
|
13
|
-
Thread.current[
|
13
|
+
Thread.current[CURRENT_BATCH_THREAD_KEY].save_context_changes
|
14
14
|
Batch.process_successful_job(@bid, job_id)
|
15
15
|
rescue
|
16
16
|
Batch.process_failed_job(@bid, job_id)
|
17
17
|
raise
|
18
18
|
ensure
|
19
|
-
Thread.current[
|
19
|
+
Thread.current[CURRENT_BATCH_THREAD_KEY] = prev_batch
|
20
20
|
end
|
21
21
|
else
|
22
22
|
block.call
|
@@ -24,7 +24,7 @@ module CanvasSync
|
|
24
24
|
end
|
25
25
|
|
26
26
|
around_enqueue do |job, block|
|
27
|
-
if (batch = Thread.current[
|
27
|
+
if (batch = Thread.current[CURRENT_BATCH_THREAD_KEY])
|
28
28
|
@bid = batch.bid
|
29
29
|
batch.increment_job_queue(job_id) if @bid
|
30
30
|
end
|
@@ -33,11 +33,11 @@ module CanvasSync
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def bid
|
36
|
-
@bid || Thread.current[
|
36
|
+
@bid || Thread.current[CURRENT_BATCH_THREAD_KEY]&.bid
|
37
37
|
end
|
38
38
|
|
39
39
|
def batch
|
40
|
-
Thread.current[
|
40
|
+
Thread.current[CURRENT_BATCH_THREAD_KEY]
|
41
41
|
end
|
42
42
|
|
43
43
|
def batch_context
|
@@ -37,16 +37,29 @@ module CanvasSync
|
|
37
37
|
insert_at(-1, new_job)
|
38
38
|
end
|
39
39
|
|
40
|
-
def insert_at(position, new_jobs)
|
40
|
+
def insert_at(position, new_jobs, *args, &blk)
|
41
41
|
chain = self.class.get_chain_parameter(base_job)
|
42
|
+
if new_jobs.is_a?(Class) || new_jobs.is_a?(String)
|
43
|
+
new_jobs = build_job_hash(new_jobs, *args, &blk)
|
44
|
+
elsif args.length > 0
|
45
|
+
raise "Unexpected number of arguments"
|
46
|
+
end
|
42
47
|
new_jobs = [new_jobs] unless new_jobs.is_a?(Array)
|
43
48
|
chain.insert(position, *new_jobs)
|
44
49
|
end
|
45
50
|
|
46
|
-
def insert(new_jobs, **kwargs)
|
47
|
-
|
48
|
-
|
49
|
-
|
51
|
+
def insert(new_jobs, *args, **kwargs, &blk)
|
52
|
+
if new_jobs.is_a?(Class) || new_jobs.is_a?(String)
|
53
|
+
job_kwargs = kwargs.except(*VALID_PLACEMENT_PARAMETERS)
|
54
|
+
args << job_kwargs if job_kwargs.present?
|
55
|
+
new_jobs = build_job_hash(new_jobs, *args, &blk)
|
56
|
+
kwargs = kwargs.slice(*VALID_PLACEMENT_PARAMETERS)
|
57
|
+
else
|
58
|
+
invalid_params = kwargs.keys - VALID_PLACEMENT_PARAMETERS
|
59
|
+
raise "Invalid placement parameters: #{invalid_params.map(&:to_s).join(', ')}" if invalid_params.present?
|
60
|
+
raise "At most one placement parameter may be provided" if kwargs.values.compact.length > 1
|
61
|
+
raise "Unexpected number of arguments" if args.length > 0
|
62
|
+
end
|
50
63
|
|
51
64
|
new_jobs = [new_jobs] unless new_jobs.is_a?(Array)
|
52
65
|
|
@@ -90,7 +103,6 @@ module CanvasSync
|
|
90
103
|
raise "Found multiple \"#{sub_type}\" jobs in the chain" if matching_jobs.count > 1
|
91
104
|
return nil if matching_jobs.count == 0
|
92
105
|
|
93
|
-
|
94
106
|
job = matching_jobs[0][0]
|
95
107
|
job = self.class.new(job) unless job.is_a?(ChainBuilder)
|
96
108
|
job
|
@@ -116,8 +128,22 @@ module CanvasSync
|
|
116
128
|
end
|
117
129
|
end
|
118
130
|
|
131
|
+
def apply_block(&blk)
|
132
|
+
return unless blk.present?
|
133
|
+
instance_exec(&blk)
|
134
|
+
end
|
135
|
+
|
119
136
|
private
|
120
137
|
|
138
|
+
def build_job_hash(job, *params, &blk)
|
139
|
+
hsh = {
|
140
|
+
job: job,
|
141
|
+
parameters: params,
|
142
|
+
}
|
143
|
+
self.class.new(hsh).apply_block(&blk) if blk.present?
|
144
|
+
hsh
|
145
|
+
end
|
146
|
+
|
121
147
|
def find_matching_jobs(search_job, parent_job = self.base_job)
|
122
148
|
return to_enum(:find_matching_jobs, search_job, parent_job) unless block_given?
|
123
149
|
|
@@ -150,6 +176,13 @@ module CanvasSync
|
|
150
176
|
end
|
151
177
|
|
152
178
|
class << self
|
179
|
+
def build(job, *args, &blk)
|
180
|
+
new(job).tap do |ch|
|
181
|
+
ch[:parameters] = args
|
182
|
+
ch.apply_block(&blk)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
153
186
|
def _job_type_definitions
|
154
187
|
@job_type_definitions ||= {}
|
155
188
|
end
|
@@ -64,18 +64,14 @@ module CanvasSync
|
|
64
64
|
let_close!
|
65
65
|
end
|
66
66
|
else
|
67
|
-
redis
|
68
|
-
r.hset(redis_key, 'keep_open', true)
|
69
|
-
end
|
67
|
+
redis.hset(redis_key, 'keep_open', true)
|
70
68
|
end
|
71
69
|
end
|
72
70
|
|
73
71
|
def let_close!
|
74
|
-
_, active_count = redis do |r|
|
75
|
-
r.
|
76
|
-
|
77
|
-
r.hincrby(redis_key, "active_count", 0)
|
78
|
-
end
|
72
|
+
_, active_count = redis.multi do |r|
|
73
|
+
r.hset(redis_key, 'keep_open', false)
|
74
|
+
r.hincrby(redis_key, "active_count", 0)
|
79
75
|
end
|
80
76
|
|
81
77
|
if active_count == 0 && pending_count == 0
|
@@ -95,35 +91,38 @@ module CanvasSync
|
|
95
91
|
end
|
96
92
|
|
97
93
|
def active_count
|
98
|
-
redis
|
99
|
-
r.hincrby(redis_key, "active_count", 0)
|
100
|
-
end
|
94
|
+
redis.hincrby(redis_key, "active_count", 0)
|
101
95
|
end
|
102
96
|
|
103
97
|
def pending_count
|
104
98
|
jobs_key = "#{redis_key}-jobs"
|
105
99
|
order = self.order || 'fifo'
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
r.zcard(jobs_key)
|
114
|
-
end
|
100
|
+
case order.to_sym
|
101
|
+
when :fifo, :lifo
|
102
|
+
redis.llen(jobs_key)
|
103
|
+
when :random
|
104
|
+
redis.scard(jobs_key)
|
105
|
+
when :priority
|
106
|
+
redis.zcard(jobs_key)
|
115
107
|
end
|
116
108
|
end
|
117
109
|
|
118
110
|
def job_checked_in(status, options)
|
119
|
-
active_count = redis do |r|
|
111
|
+
active_count, pending_count = redis do |r|
|
120
112
|
return unless r.exists?(redis_key)
|
121
|
-
|
113
|
+
|
114
|
+
# Make sure this is loaded outside of the pipeline
|
115
|
+
self.order
|
116
|
+
|
117
|
+
redis.multi do
|
118
|
+
r.hincrby(redis_key, "active_count", -1)
|
119
|
+
self.pending_count
|
120
|
+
end
|
122
121
|
end
|
123
122
|
|
124
123
|
added_count = refill_allotment
|
125
|
-
if active_count == 0 && added_count == 0
|
126
|
-
if clean_when_empty && redis
|
124
|
+
if active_count == 0 && added_count == 0 && pending_count == 0
|
125
|
+
if clean_when_empty && redis.hget(redis_key, 'keep_open') != 'true'
|
127
126
|
cleanup_redis
|
128
127
|
end
|
129
128
|
end
|
@@ -175,18 +174,16 @@ module CanvasSync
|
|
175
174
|
job_json = JSON.unparse(ActiveJob::Arguments.serialize([job_desc]))
|
176
175
|
order = self.order
|
177
176
|
|
178
|
-
redis do |r|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
r.zadd(jobs_key, job_desc[:priority] || 0, job_json)
|
187
|
-
end
|
188
|
-
r.expire(jobs_key, Batch::BID_EXPIRE_TTL)
|
177
|
+
redis.multi do |r|
|
178
|
+
case order.to_sym
|
179
|
+
when :fifo, :lifo
|
180
|
+
r.rpush(jobs_key, job_json)
|
181
|
+
when :random
|
182
|
+
r.sadd(jobs_key, job_json)
|
183
|
+
when :priority
|
184
|
+
r.zadd(jobs_key, job_desc[:priority] || 0, job_json)
|
189
185
|
end
|
186
|
+
r.expire(jobs_key, Batch::BID_EXPIRE_TTL)
|
190
187
|
end
|
191
188
|
end
|
192
189
|
|
@@ -194,18 +191,15 @@ module CanvasSync
|
|
194
191
|
jobs_key = "#{redis_key}-jobs"
|
195
192
|
order = self.order
|
196
193
|
|
197
|
-
job_json =
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
when :priority
|
207
|
-
r.zpopmax(jobs_key)
|
208
|
-
end
|
194
|
+
job_json = case order.to_sym
|
195
|
+
when :fifo
|
196
|
+
redis.lpop(jobs_key)
|
197
|
+
when :lifo
|
198
|
+
redis.rpop(jobs_key)
|
199
|
+
when :random
|
200
|
+
redis.spop(jobs_key)
|
201
|
+
when :priority
|
202
|
+
redis.zpopmax(jobs_key)
|
209
203
|
end
|
210
204
|
|
211
205
|
return nil unless job_json.present?
|
@@ -218,13 +212,9 @@ module CanvasSync
|
|
218
212
|
end
|
219
213
|
delegate :redis, to: :class
|
220
214
|
|
221
|
-
protected
|
222
|
-
|
223
215
|
def flush_pending_attrs
|
224
216
|
super
|
225
|
-
redis
|
226
|
-
r.zadd("pools", created_at, pid)
|
227
|
-
end
|
217
|
+
redis.zadd("pools", created_at, pid)
|
228
218
|
end
|
229
219
|
|
230
220
|
private
|
@@ -8,11 +8,11 @@ module CanvasSync
|
|
8
8
|
module Sidekiq
|
9
9
|
module WorkerExtension
|
10
10
|
def bid
|
11
|
-
Thread.current[
|
11
|
+
Thread.current[CURRENT_BATCH_THREAD_KEY].bid
|
12
12
|
end
|
13
13
|
|
14
14
|
def batch
|
15
|
-
Thread.current[
|
15
|
+
Thread.current[CURRENT_BATCH_THREAD_KEY]
|
16
16
|
end
|
17
17
|
|
18
18
|
def batch_context
|
@@ -42,7 +42,7 @@ module CanvasSync
|
|
42
42
|
|
43
43
|
class ClientMiddleware
|
44
44
|
def call(_worker, msg, _queue, _redis_pool = nil)
|
45
|
-
if (batch = Thread.current[
|
45
|
+
if (batch = Thread.current[CURRENT_BATCH_THREAD_KEY]) && should_handle_batch?(msg)
|
46
46
|
batch.increment_job_queue(msg['jid']) if (msg[:bid] = batch.bid)
|
47
47
|
end
|
48
48
|
yield
|
@@ -57,17 +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[
|
60
|
+
prev_batch = Thread.current[CURRENT_BATCH_THREAD_KEY]
|
61
61
|
begin
|
62
|
-
Thread.current[
|
62
|
+
Thread.current[CURRENT_BATCH_THREAD_KEY] = Batch.new(bid)
|
63
63
|
yield
|
64
|
-
Thread.current[
|
64
|
+
Thread.current[CURRENT_BATCH_THREAD_KEY].save_context_changes
|
65
65
|
Batch.process_successful_job(bid, msg['jid'])
|
66
66
|
rescue
|
67
67
|
Batch.process_failed_job(bid, msg['jid'])
|
68
68
|
raise
|
69
69
|
ensure
|
70
|
-
Thread.current[
|
70
|
+
Thread.current[CURRENT_BATCH_THREAD_KEY] = prev_batch
|
71
71
|
end
|
72
72
|
else
|
73
73
|
yield
|
@@ -14,6 +14,12 @@ module CanvasSync
|
|
14
14
|
globals[:updated_after] = last_batch&.started_at&.iso8601
|
15
15
|
end
|
16
16
|
|
17
|
+
# Refuse to run syncs of the same genre if there is a running full sync
|
18
|
+
if last_full_sync_record&.status == 'processing' && last_full_sync > 12.hours.ago
|
19
|
+
Rails.logger.warn("Attempted to start a '#{genre}' sync while a full-sync is still processing.")
|
20
|
+
return
|
21
|
+
end
|
22
|
+
|
17
23
|
if should_full_sync?(globals[:full_sync_every])
|
18
24
|
globals[:updated_after] = nil
|
19
25
|
end
|
@@ -25,6 +31,8 @@ module CanvasSync
|
|
25
31
|
status: 'processing',
|
26
32
|
)
|
27
33
|
|
34
|
+
globals[:sync_batch_id] = sync_batch.id
|
35
|
+
|
28
36
|
JobBatches::Batch.new.tap do |b|
|
29
37
|
b.description = "CanvasSync Root Batch (SyncBatch##{sync_batch.id})"
|
30
38
|
b.on(:complete, "#{self.class.to_s}.batch_completed", sync_batch_id: sync_batch.id)
|
@@ -62,7 +70,7 @@ module CanvasSync
|
|
62
70
|
end
|
63
71
|
|
64
72
|
def last_full_sync_record
|
65
|
-
@last_full_sync_record ||= SyncBatch.where(status: 'completed', full_sync: true, batch_genre: genre).last
|
73
|
+
@last_full_sync_record ||= SyncBatch.where(status: ['completed', 'processing'], full_sync: true, batch_genre: genre).last
|
66
74
|
end
|
67
75
|
|
68
76
|
def last_full_sync
|
@@ -23,23 +23,7 @@ module CanvasSync
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
|
27
|
-
context = options[:context] || {}
|
28
|
-
if options[:term_scope]
|
29
|
-
Term.send(options[:term_scope]).find_each.map do |term|
|
30
|
-
local_context = context.merge(canvas_term_id: get_term_id(term))
|
31
|
-
JobBatches::ConcurrentBatchJob.perform_now(jobs, context: local_context)
|
32
|
-
end
|
33
|
-
else
|
34
|
-
JobBatches::ConcurrentBatchJob.perform_now(jobs, context: context)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
protected
|
40
|
-
|
41
|
-
def get_term_id(term)
|
42
|
-
term.try(:canvas_id) || term.canvas_term_id
|
26
|
+
TermBatchesJob.perform_now(options)
|
43
27
|
end
|
44
28
|
end
|
45
29
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module CanvasSync
|
2
|
+
module Jobs
|
3
|
+
class TermBatchesJob < CanvasSync::Job
|
4
|
+
def perform(options)
|
5
|
+
if (jobs = options[:sub_jobs]).present?
|
6
|
+
context = options[:context] || {}
|
7
|
+
if options[:term_scope]
|
8
|
+
Term.send(options[:term_scope]).find_each.map do |term|
|
9
|
+
local_context = context.merge(canvas_term_id: get_term_id(term))
|
10
|
+
JobBatches::ConcurrentBatchJob.perform_now(jobs, context: local_context)
|
11
|
+
end
|
12
|
+
else
|
13
|
+
JobBatches::ConcurrentBatchJob.perform_now(jobs, context: context)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def get_term_id(term)
|
19
|
+
term.try(:canvas_id) || term.canvas_term_id
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|