canvas_sync 0.21.1 → 0.22.0.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/concerns/auto_relations.rb +11 -0
- data/lib/canvas_sync/config.rb +3 -5
- data/lib/canvas_sync/generators/templates/models/rubric.rb +2 -1
- data/lib/canvas_sync/job_batches/batch.rb +432 -402
- data/lib/canvas_sync/job_batches/callback.rb +100 -114
- data/lib/canvas_sync/job_batches/chain_builder.rb +194 -196
- data/lib/canvas_sync/job_batches/{active_job.rb → compat/active_job.rb} +2 -2
- data/lib/canvas_sync/job_batches/{sidekiq → compat/sidekiq}/web/helpers.rb +1 -1
- data/lib/canvas_sync/job_batches/{sidekiq → compat/sidekiq}/web.rb +3 -3
- data/lib/canvas_sync/job_batches/{sidekiq.rb → compat/sidekiq.rb} +35 -22
- data/lib/canvas_sync/job_batches/compat.rb +20 -0
- data/lib/canvas_sync/job_batches/context_hash.rb +124 -126
- data/lib/canvas_sync/job_batches/jobs/base_job.rb +2 -4
- data/lib/canvas_sync/job_batches/jobs/concurrent_batch_job.rb +14 -16
- data/lib/canvas_sync/job_batches/jobs/managed_batch_job.rb +125 -127
- data/lib/canvas_sync/job_batches/jobs/serial_batch_job.rb +14 -16
- data/lib/canvas_sync/job_batches/pool.rb +193 -195
- data/lib/canvas_sync/job_batches/redis_model.rb +50 -52
- data/lib/canvas_sync/job_batches/redis_script.rb +129 -131
- data/lib/canvas_sync/job_batches/status.rb +85 -87
- data/lib/canvas_sync/job_uniqueness/compat/active_job.rb +75 -0
- data/lib/canvas_sync/job_uniqueness/compat/sidekiq.rb +135 -0
- data/lib/canvas_sync/job_uniqueness/compat.rb +20 -0
- data/lib/canvas_sync/job_uniqueness/configuration.rb +25 -0
- data/lib/canvas_sync/job_uniqueness/job_uniqueness.rb +47 -0
- data/lib/canvas_sync/job_uniqueness/lock_context.rb +171 -0
- data/lib/canvas_sync/job_uniqueness/locksmith.rb +92 -0
- data/lib/canvas_sync/job_uniqueness/on_conflict/base.rb +32 -0
- data/lib/canvas_sync/job_uniqueness/on_conflict/log.rb +13 -0
- data/lib/canvas_sync/job_uniqueness/on_conflict/null_strategy.rb +9 -0
- data/lib/canvas_sync/job_uniqueness/on_conflict/raise.rb +11 -0
- data/lib/canvas_sync/job_uniqueness/on_conflict/reject.rb +21 -0
- data/lib/canvas_sync/job_uniqueness/on_conflict/reschedule.rb +20 -0
- data/lib/canvas_sync/job_uniqueness/on_conflict.rb +41 -0
- data/lib/canvas_sync/job_uniqueness/strategy/base.rb +104 -0
- data/lib/canvas_sync/job_uniqueness/strategy/until_and_while_executing.rb +35 -0
- data/lib/canvas_sync/job_uniqueness/strategy/until_executed.rb +20 -0
- data/lib/canvas_sync/job_uniqueness/strategy/until_executing.rb +20 -0
- data/lib/canvas_sync/job_uniqueness/strategy/until_expired.rb +16 -0
- data/lib/canvas_sync/job_uniqueness/strategy/while_executing.rb +26 -0
- data/lib/canvas_sync/job_uniqueness/strategy.rb +27 -0
- data/lib/canvas_sync/job_uniqueness/unique_job_common.rb +79 -0
- data/lib/canvas_sync/misc_helper.rb +1 -1
- data/lib/canvas_sync/version.rb +1 -1
- data/lib/canvas_sync.rb +4 -3
- data/spec/dummy/app/models/rubric.rb +2 -1
- data/spec/dummy/config/environments/test.rb +1 -1
- data/spec/job_batching/batch_spec.rb +49 -7
- data/spec/job_batching/{active_job_spec.rb → compat/active_job_spec.rb} +2 -2
- data/spec/job_batching/{sidekiq_spec.rb → compat/sidekiq_spec.rb} +14 -12
- data/spec/job_batching/flow_spec.rb +1 -1
- data/spec/job_batching/integration_helper.rb +1 -1
- data/spec/job_batching/status_spec.rb +2 -2
- data/spec/job_uniqueness/compat/active_job_spec.rb +49 -0
- data/spec/job_uniqueness/compat/sidekiq_spec.rb +68 -0
- data/spec/job_uniqueness/lock_context_spec.rb +95 -0
- data/spec/job_uniqueness/on_conflict/log_spec.rb +11 -0
- data/spec/job_uniqueness/on_conflict/raise_spec.rb +10 -0
- data/spec/job_uniqueness/on_conflict/reschedule_spec.rb +24 -0
- data/spec/job_uniqueness/on_conflict_spec.rb +16 -0
- data/spec/job_uniqueness/spec_helper.rb +14 -0
- data/spec/job_uniqueness/strategy/base_spec.rb +100 -0
- data/spec/job_uniqueness/strategy/until_and_while_executing_spec.rb +48 -0
- data/spec/job_uniqueness/strategy/until_executed_spec.rb +23 -0
- data/spec/job_uniqueness/strategy/until_executing_spec.rb +23 -0
- data/spec/job_uniqueness/strategy/until_expired_spec.rb +23 -0
- data/spec/job_uniqueness/strategy/while_executing_spec.rb +33 -0
- data/spec/job_uniqueness/support/lock_strategy.rb +28 -0
- data/spec/job_uniqueness/support/on_conflict.rb +24 -0
- data/spec/job_uniqueness/support/test_worker.rb +19 -0
- data/spec/job_uniqueness/unique_job_common_spec.rb +45 -0
- data/spec/spec_helper.rb +1 -1
- metadata +278 -204
- /data/lib/canvas_sync/job_batches/{sidekiq → compat/sidekiq}/web/batches_assets/css/styles.less +0 -0
- /data/lib/canvas_sync/job_batches/{sidekiq → compat/sidekiq}/web/batches_assets/js/batch_tree.js +0 -0
- /data/lib/canvas_sync/job_batches/{sidekiq → compat/sidekiq}/web/batches_assets/js/util.js +0 -0
- /data/lib/canvas_sync/job_batches/{sidekiq → compat/sidekiq}/web/views/_batch_tree.erb +0 -0
- /data/lib/canvas_sync/job_batches/{sidekiq → compat/sidekiq}/web/views/_batches_table.erb +0 -0
- /data/lib/canvas_sync/job_batches/{sidekiq → compat/sidekiq}/web/views/_common.erb +0 -0
- /data/lib/canvas_sync/job_batches/{sidekiq → compat/sidekiq}/web/views/_jobs_table.erb +0 -0
- /data/lib/canvas_sync/job_batches/{sidekiq → compat/sidekiq}/web/views/_pagination.erb +0 -0
- /data/lib/canvas_sync/job_batches/{sidekiq → compat/sidekiq}/web/views/batch.erb +0 -0
- /data/lib/canvas_sync/job_batches/{sidekiq → compat/sidekiq}/web/views/batches.erb +0 -0
- /data/lib/canvas_sync/job_batches/{sidekiq → compat/sidekiq}/web/views/pool.erb +0 -0
- /data/lib/canvas_sync/job_batches/{sidekiq → compat/sidekiq}/web/views/pools.erb +0 -0
@@ -1,159 +1,157 @@
|
|
1
|
-
module CanvasSync
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
end
|
13
|
-
|
14
|
-
# Local is "the nearest batch with a context value"
|
15
|
-
# This allows for, for example, SerialBatchJob to have a modifiable context stored on it's main Batch
|
16
|
-
# that can be accessed transparently from one of it's internal, context-less Batches
|
17
|
-
def local_bid
|
18
|
-
bid = @bid_stack[-1]
|
19
|
-
while bid.present?
|
20
|
-
bhash = resolve_hash(bid)
|
21
|
-
return bid if bhash
|
22
|
-
bid = get_parent_bid(bid)
|
23
|
-
end
|
24
|
-
nil
|
25
|
-
end
|
1
|
+
module CanvasSync::JobBatches
|
2
|
+
class ContextHash
|
3
|
+
delegate_missing_to :flatten
|
4
|
+
|
5
|
+
def initialize(bid, hash = nil)
|
6
|
+
@bid_stack = [bid]
|
7
|
+
@hash_map = {}
|
8
|
+
@dirty = false
|
9
|
+
@flattened = nil
|
10
|
+
@hash_map[bid] = hash.with_indifferent_access if hash
|
11
|
+
end
|
26
12
|
|
27
|
-
|
28
|
-
|
29
|
-
|
13
|
+
# Local is "the nearest batch with a context value"
|
14
|
+
# This allows for, for example, SerialBatchJob to have a modifiable context stored on it's main Batch
|
15
|
+
# that can be accessed transparently from one of it's internal, context-less Batches
|
16
|
+
def local_bid
|
17
|
+
bid = @bid_stack[-1]
|
18
|
+
while bid.present?
|
19
|
+
bhash = resolve_hash(bid)
|
20
|
+
return bid if bhash
|
21
|
+
bid = get_parent_bid(bid)
|
22
|
+
end
|
23
|
+
nil
|
24
|
+
end
|
30
25
|
|
31
|
-
|
32
|
-
|
33
|
-
|
26
|
+
def local
|
27
|
+
@hash_map[local_bid]
|
28
|
+
end
|
34
29
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
end
|
30
|
+
def own
|
31
|
+
resolve_hash(@bid_stack[-1]) || {}
|
32
|
+
end
|
39
33
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
self
|
45
|
-
end
|
34
|
+
def set_local(new_hash)
|
35
|
+
@dirty = true
|
36
|
+
local.clear.merge!(new_hash)
|
37
|
+
end
|
46
38
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
39
|
+
def clear
|
40
|
+
local.clear
|
41
|
+
@flattened = nil
|
42
|
+
@dirty = true
|
43
|
+
self
|
44
|
+
end
|
52
45
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
bid = get_parent_bid(bid)
|
59
|
-
end
|
60
|
-
nil
|
61
|
-
end
|
46
|
+
def []=(key, value)
|
47
|
+
@flattened = nil
|
48
|
+
@dirty = true
|
49
|
+
local[key] = value
|
50
|
+
end
|
62
51
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
52
|
+
def [](key)
|
53
|
+
bid = @bid_stack[-1]
|
54
|
+
while bid.present?
|
55
|
+
bhash = resolve_hash(bid)
|
56
|
+
return bhash[key] if bhash&.key?(key)
|
57
|
+
bid = get_parent_bid(bid)
|
67
58
|
end
|
59
|
+
nil
|
60
|
+
end
|
68
61
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
end
|
62
|
+
def reload!
|
63
|
+
@dirty = false
|
64
|
+
@hash_map = {}
|
65
|
+
self
|
66
|
+
end
|
75
67
|
|
76
|
-
|
77
|
-
|
68
|
+
def save!(force: false)
|
69
|
+
return unless dirty? || force
|
70
|
+
Batch.redis do |r|
|
71
|
+
r.hset("BID-#{local_bid}", 'context', JSON.unparse(local))
|
78
72
|
end
|
73
|
+
end
|
79
74
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
end
|
75
|
+
def dirty?
|
76
|
+
@dirty
|
77
|
+
end
|
84
78
|
|
85
|
-
|
86
|
-
|
79
|
+
def is_a?(arg)
|
80
|
+
return true if Hash <= arg
|
81
|
+
super
|
82
|
+
end
|
87
83
|
|
88
|
-
|
89
|
-
|
90
|
-
@bid_stack.compact.each do |bid|
|
91
|
-
flattened.merge!(@hash_map[bid]) if @hash_map[bid]
|
92
|
-
end
|
93
|
-
flattened.freeze
|
84
|
+
def flatten
|
85
|
+
return @flattened if @flattened
|
94
86
|
|
95
|
-
|
87
|
+
load_all
|
88
|
+
flattened = {}
|
89
|
+
@bid_stack.compact.each do |bid|
|
90
|
+
flattened.merge!(@hash_map[bid]) if @hash_map[bid]
|
96
91
|
end
|
92
|
+
flattened.freeze
|
97
93
|
|
98
|
-
|
99
|
-
|
100
|
-
end
|
94
|
+
@flattened = flattened.with_indifferent_access
|
95
|
+
end
|
101
96
|
|
102
|
-
|
97
|
+
def to_h
|
98
|
+
flatten
|
99
|
+
end
|
103
100
|
|
104
|
-
|
105
|
-
resolve_hash(get_parent_bid(bid)).freeze
|
106
|
-
end
|
101
|
+
private
|
107
102
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
103
|
+
def get_parent_hash(bid)
|
104
|
+
resolve_hash(get_parent_bid(bid)).freeze
|
105
|
+
end
|
106
|
+
|
107
|
+
def get_parent_bid(bid)
|
108
|
+
index = @bid_stack.index(bid)
|
109
|
+
raise "Invalid BID #{bid}" if index.nil? # Sanity Check - this shouldn't happen
|
110
|
+
|
111
|
+
index -= 1
|
112
|
+
if index >= 0
|
113
|
+
@bid_stack[index]
|
114
|
+
else
|
115
|
+
pbid = Batch.redis do |r|
|
116
|
+
callback_params = JSON.parse(r.hget("BID-#{bid}", "callback_params") || "{}")
|
117
|
+
callback_params['for_bid'] || r.hget("BID-#{bid}", "parent_bid")
|
122
118
|
end
|
119
|
+
@bid_stack.unshift(pbid)
|
120
|
+
pbid
|
123
121
|
end
|
122
|
+
end
|
124
123
|
|
125
|
-
|
126
|
-
|
127
|
-
|
124
|
+
def resolve_hash(bid)
|
125
|
+
return nil unless bid.present?
|
126
|
+
return @hash_map[bid] if @hash_map.key?(bid)
|
128
127
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
end
|
128
|
+
context_json, editable = Batch.redis do |r|
|
129
|
+
r.multi do |r|
|
130
|
+
r.hget("BID-#{bid}", "context")
|
131
|
+
r.hget("BID-#{bid}", "allow_context_changes")
|
134
132
|
end
|
133
|
+
end
|
135
134
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
end
|
142
|
-
context_hash.freeze unless editable
|
143
|
-
|
144
|
-
@hash_map[bid] = context_hash
|
145
|
-
else
|
146
|
-
@hash_map[bid] = nil
|
135
|
+
if context_json.present?
|
136
|
+
context_hash = JSON.parse(context_json)
|
137
|
+
context_hash = context_hash.with_indifferent_access
|
138
|
+
context_hash.each do |k, v|
|
139
|
+
v.freeze
|
147
140
|
end
|
141
|
+
context_hash.freeze unless editable
|
142
|
+
|
143
|
+
@hash_map[bid] = context_hash
|
144
|
+
else
|
145
|
+
@hash_map[bid] = nil
|
148
146
|
end
|
147
|
+
end
|
149
148
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
end
|
155
|
-
@hash_map
|
149
|
+
def load_all
|
150
|
+
resolve_hash(@bid_stack[0]).freeze
|
151
|
+
while @bid_stack[0].present?
|
152
|
+
get_parent_hash(@bid_stack[0])
|
156
153
|
end
|
154
|
+
@hash_map
|
157
155
|
end
|
158
156
|
end
|
159
157
|
end
|
@@ -1,22 +1,20 @@
|
|
1
1
|
require_relative './base_job'
|
2
2
|
|
3
|
-
module CanvasSync
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
end
|
3
|
+
module CanvasSync::JobBatches
|
4
|
+
class ConcurrentBatchJob < BaseJob
|
5
|
+
def self.make_batch(sub_jobs, **kwargs, &blk)
|
6
|
+
ManagedBatchJob.make_batch(
|
7
|
+
sub_jobs,
|
8
|
+
**kwargs,
|
9
|
+
ordered: false,
|
10
|
+
concurrency: true,
|
11
|
+
desc_prefix: 'ConcurrentBatchJob: ',
|
12
|
+
&blk
|
13
|
+
)
|
14
|
+
end
|
16
15
|
|
17
|
-
|
18
|
-
|
19
|
-
end
|
16
|
+
def perform(sub_jobs, **kwargs)
|
17
|
+
self.class.make_batch(sub_jobs, **kwargs)
|
20
18
|
end
|
21
19
|
end
|
22
20
|
end
|
@@ -1,170 +1,168 @@
|
|
1
1
|
require_relative './base_job'
|
2
2
|
|
3
|
-
module CanvasSync
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
3
|
+
module CanvasSync::JobBatches
|
4
|
+
class ManagedBatchJob < BaseJob
|
5
|
+
def self.make_batch(sub_jobs, ordered: true, concurrency: nil, context: nil, preflight_check: nil, desc_prefix: nil, &blk)
|
6
|
+
desc_prefix ||= ''
|
7
|
+
|
8
|
+
if concurrency == 0 || concurrency == nil || concurrency == true
|
9
|
+
concurrency = sub_jobs.count
|
10
|
+
elsif concurrency == false
|
11
|
+
concurrency = 1
|
12
|
+
end
|
13
|
+
|
14
|
+
root_batch = Batch.new
|
15
|
+
man_batch_id = nil
|
16
|
+
|
17
|
+
if concurrency < sub_jobs.count
|
18
|
+
man_batch_id = SecureRandom.urlsafe_base64(10)
|
14
19
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
r.expire("MNGBID-#{man_batch_id}", Batch::BID_EXPIRE_TTL)
|
28
|
-
|
29
|
-
mapped_sub_jobs = sub_jobs.each_with_index.map do |j, i|
|
30
|
-
j['_mngbid_index_'] = i # This allows duplicate jobs when a Redis Set is used
|
31
|
-
j = ::ActiveJob::Arguments.serialize([j])
|
32
|
-
JSON.unparse(j)
|
33
|
-
end
|
34
|
-
if ordered
|
35
|
-
r.rpush("MNGBID-#{man_batch_id}-jobs", mapped_sub_jobs)
|
36
|
-
else
|
37
|
-
r.sadd("MNGBID-#{man_batch_id}-jobs", mapped_sub_jobs)
|
38
|
-
end
|
39
|
-
r.expire("MNGBID-#{man_batch_id}-jobs", Batch::BID_EXPIRE_TTL)
|
20
|
+
Batch.redis do |r|
|
21
|
+
r.multi do |r|
|
22
|
+
r.hset("MNGBID-#{man_batch_id}", "root_bid", root_batch.bid)
|
23
|
+
r.hset("MNGBID-#{man_batch_id}", "ordered", ordered ? 1 : 0)
|
24
|
+
r.hset("MNGBID-#{man_batch_id}", "concurrency", concurrency)
|
25
|
+
r.hset("MNGBID-#{man_batch_id}", "preflight_check", preflight_check) if preflight_check.present?
|
26
|
+
r.expire("MNGBID-#{man_batch_id}", Batch::BID_EXPIRE_TTL)
|
27
|
+
|
28
|
+
mapped_sub_jobs = sub_jobs.each_with_index.map do |j, i|
|
29
|
+
j['_mngbid_index_'] = i # This allows duplicate jobs when a Redis Set is used
|
30
|
+
j = ::ActiveJob::Arguments.serialize([j])
|
31
|
+
JSON.unparse(j)
|
40
32
|
end
|
33
|
+
if ordered
|
34
|
+
r.rpush("MNGBID-#{man_batch_id}-jobs", mapped_sub_jobs)
|
35
|
+
else
|
36
|
+
r.sadd("MNGBID-#{man_batch_id}-jobs", mapped_sub_jobs)
|
37
|
+
end
|
38
|
+
r.expire("MNGBID-#{man_batch_id}-jobs", Batch::BID_EXPIRE_TTL)
|
41
39
|
end
|
40
|
+
end
|
42
41
|
|
43
|
-
|
44
|
-
|
42
|
+
root_batch.allow_context_changes = (concurrency == 1)
|
43
|
+
root_batch.on(:success, "#{to_s}.cleanup_redis", managed_batch_id: man_batch_id)
|
45
44
|
|
46
|
-
|
47
|
-
|
45
|
+
desc_prefix = "MGD(#{man_batch_id}): #{desc_prefix}"
|
46
|
+
end
|
48
47
|
|
49
|
-
|
48
|
+
root_batch.context = context
|
50
49
|
|
51
|
-
|
50
|
+
blk.call(ManagedBatchProxy.new(root_batch)) if blk.present?
|
52
51
|
|
53
|
-
|
52
|
+
root_batch.description = "#{desc_prefix}#{root_batch.description || 'Root'}"
|
54
53
|
|
55
|
-
|
54
|
+
root_batch.context["managed_batch_bid"] = man_batch_id if man_batch_id
|
56
55
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
end
|
56
|
+
if concurrency < sub_jobs.count
|
57
|
+
root_batch.jobs {}
|
58
|
+
concurrency.times do
|
59
|
+
perform_next_sequence_job(man_batch_id, skip_preflight: true)
|
60
|
+
end
|
61
|
+
else
|
62
|
+
root_batch.jobs do
|
63
|
+
sub_jobs.each do |j|
|
64
|
+
ChainBuilder.enqueue_job(j)
|
67
65
|
end
|
68
66
|
end
|
69
|
-
|
70
|
-
root_batch
|
71
67
|
end
|
72
68
|
|
73
|
-
|
74
|
-
|
75
|
-
end
|
69
|
+
root_batch
|
70
|
+
end
|
76
71
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
r.del(
|
81
|
-
"MNGBID-#{man_batch_id}",
|
82
|
-
"MNGBID-#{man_batch_id}-jobs",
|
83
|
-
)
|
84
|
-
end
|
85
|
-
end
|
72
|
+
def perform(sub_jobs, **kwargs)
|
73
|
+
self.class.make_batch(sub_jobs, **kwargs)
|
74
|
+
end
|
86
75
|
|
87
|
-
|
88
|
-
|
89
|
-
|
76
|
+
def self.cleanup_redis(status, options)
|
77
|
+
man_batch_id = options['managed_batch_id']
|
78
|
+
Batch.redis do |r|
|
79
|
+
r.del(
|
80
|
+
"MNGBID-#{man_batch_id}",
|
81
|
+
"MNGBID-#{man_batch_id}-jobs",
|
82
|
+
)
|
90
83
|
end
|
84
|
+
end
|
91
85
|
|
92
|
-
|
86
|
+
def self.job_succeeded_callback(status, options)
|
87
|
+
man_batch_id = options['managed_batch_id']
|
88
|
+
perform_next_sequence_job(man_batch_id)
|
89
|
+
end
|
93
90
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
91
|
+
protected
|
92
|
+
|
93
|
+
def self.perform_next_sequence_job(man_batch_id, skip_preflight: false)
|
94
|
+
root_bid, ordered, preflight_check = Batch.redis do |r|
|
95
|
+
r.multi do |r|
|
96
|
+
r.hget("MNGBID-#{man_batch_id}", "root_bid")
|
97
|
+
r.hget("MNGBID-#{man_batch_id}", "ordered")
|
98
|
+
r.hget("MNGBID-#{man_batch_id}", "preflight_check")
|
101
99
|
end
|
100
|
+
end
|
102
101
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
else
|
108
|
-
clazz = Object
|
109
|
-
method_name = preflight_check
|
110
|
-
end
|
111
|
-
preflight_check = ->(*args) { clazz.send(method_name, *args) }
|
102
|
+
if !skip_preflight && preflight_check.present?
|
103
|
+
if preflight_check.include?(".")
|
104
|
+
clazz, method_name = preflight_check.split('.')
|
105
|
+
clazz = clazz.constantize
|
112
106
|
else
|
113
|
-
|
107
|
+
clazz = Object
|
108
|
+
method_name = preflight_check
|
114
109
|
end
|
110
|
+
preflight_check = ->(*args) { clazz.send(method_name, *args) }
|
111
|
+
else
|
112
|
+
preflight_check = ->(*args) { true }
|
113
|
+
end
|
115
114
|
|
116
|
-
|
115
|
+
ordered = CanvasSync::MiscHelper.to_boolean(ordered)
|
117
116
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
end
|
117
|
+
loop do
|
118
|
+
next_job_json = Batch.redis do |r|
|
119
|
+
if ordered
|
120
|
+
r.lpop("MNGBID-#{man_batch_id}-jobs")
|
121
|
+
else
|
122
|
+
r.spop("MNGBID-#{man_batch_id}-jobs")
|
125
123
|
end
|
124
|
+
end
|
126
125
|
|
127
|
-
|
126
|
+
break unless next_job_json.present?
|
128
127
|
|
129
|
-
|
130
|
-
|
128
|
+
next_job = JSON.parse(next_job_json)
|
129
|
+
next_job = ::ActiveJob::Arguments.deserialize(next_job)[0]
|
131
130
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
131
|
+
preflight_result = preflight_check.call(next_job)
|
132
|
+
if preflight_result == :abort
|
133
|
+
cleanup_redis(nil, { "managed_batch_id" => man_batch_id })
|
134
|
+
break
|
135
|
+
elsif !preflight_check
|
136
|
+
next
|
137
|
+
end
|
139
138
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
end
|
139
|
+
Batch.new(root_bid).jobs do
|
140
|
+
Batch.new.tap do |batch|
|
141
|
+
batch.description = "Managed Batch Fiber (#{man_batch_id})"
|
142
|
+
batch.on(:success, "#{self.to_s}.job_succeeded_callback", managed_batch_id: man_batch_id)
|
143
|
+
batch.jobs do
|
144
|
+
ChainBuilder.enqueue_job(next_job)
|
147
145
|
end
|
148
146
|
end
|
149
|
-
|
150
|
-
break
|
151
147
|
end
|
152
|
-
end
|
153
148
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
end
|
149
|
+
break
|
150
|
+
end
|
151
|
+
end
|
158
152
|
|
159
|
-
|
153
|
+
class ManagedBatchProxy
|
154
|
+
def initialize(real_batch)
|
155
|
+
@real_batch = real_batch
|
156
|
+
end
|
160
157
|
|
161
|
-
|
162
|
-
raise "Managed Batches do not support calling .jobs directly!"
|
163
|
-
end
|
158
|
+
delegate_missing_to :real_batch
|
164
159
|
|
165
|
-
|
166
|
-
|
160
|
+
def jobs
|
161
|
+
raise "Managed Batches do not support calling .jobs directly!"
|
167
162
|
end
|
163
|
+
|
164
|
+
private
|
165
|
+
attr_reader :real_batch
|
168
166
|
end
|
169
167
|
end
|
170
168
|
end
|
@@ -1,22 +1,20 @@
|
|
1
1
|
require_relative './base_job'
|
2
2
|
|
3
|
-
module CanvasSync
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
end
|
3
|
+
module CanvasSync::JobBatches
|
4
|
+
class SerialBatchJob < BaseJob
|
5
|
+
def self.make_batch(sub_jobs, **kwargs, &blk)
|
6
|
+
ManagedBatchJob.make_batch(
|
7
|
+
sub_jobs,
|
8
|
+
**kwargs,
|
9
|
+
ordered: true,
|
10
|
+
concurrency: false,
|
11
|
+
desc_prefix: 'SerialBatchJob: ',
|
12
|
+
&blk
|
13
|
+
)
|
14
|
+
end
|
16
15
|
|
17
|
-
|
18
|
-
|
19
|
-
end
|
16
|
+
def perform(sub_jobs, **kwargs)
|
17
|
+
self.class.make_batch(sub_jobs, **kwargs)
|
20
18
|
end
|
21
19
|
end
|
22
20
|
end
|