canvas_sync 0.16.2 → 0.17.0.beta3
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 +49 -137
- data/app/models/canvas_sync/sync_batch.rb +5 -0
- data/db/migrate/20170915210836_create_canvas_sync_job_log.rb +12 -31
- data/db/migrate/20180725155729_add_job_id_to_canvas_sync_job_logs.rb +4 -13
- data/db/migrate/20190916154829_add_fork_count_to_canvas_sync_job_logs.rb +3 -11
- data/db/migrate/20201018210836_create_canvas_sync_sync_batches.rb +11 -0
- data/lib/canvas_sync.rb +36 -118
- data/lib/canvas_sync/concerns/api_syncable.rb +27 -0
- data/lib/canvas_sync/job.rb +5 -5
- data/lib/canvas_sync/job_batches/batch.rb +399 -0
- data/lib/canvas_sync/job_batches/batch_aware_job.rb +62 -0
- data/lib/canvas_sync/job_batches/callback.rb +153 -0
- data/lib/canvas_sync/job_batches/chain_builder.rb +210 -0
- data/lib/canvas_sync/job_batches/context_hash.rb +147 -0
- data/lib/canvas_sync/job_batches/jobs/base_job.rb +7 -0
- data/lib/canvas_sync/job_batches/jobs/concurrent_batch_job.rb +18 -0
- data/lib/canvas_sync/job_batches/jobs/serial_batch_job.rb +73 -0
- data/lib/canvas_sync/job_batches/sidekiq.rb +93 -0
- data/lib/canvas_sync/job_batches/status.rb +63 -0
- data/lib/canvas_sync/jobs/begin_sync_chain_job.rb +34 -0
- data/lib/canvas_sync/jobs/report_checker.rb +3 -6
- data/lib/canvas_sync/jobs/report_processor_job.rb +2 -5
- data/lib/canvas_sync/jobs/report_starter.rb +27 -19
- data/lib/canvas_sync/jobs/sync_accounts_job.rb +3 -5
- data/lib/canvas_sync/jobs/sync_admins_job.rb +2 -4
- data/lib/canvas_sync/jobs/sync_assignment_groups_job.rb +2 -4
- data/lib/canvas_sync/jobs/sync_assignments_job.rb +2 -4
- data/lib/canvas_sync/jobs/sync_context_module_items_job.rb +2 -4
- data/lib/canvas_sync/jobs/sync_context_modules_job.rb +2 -4
- data/lib/canvas_sync/jobs/sync_provisioning_report_job.rb +5 -35
- data/lib/canvas_sync/jobs/sync_roles_job.rb +2 -5
- data/lib/canvas_sync/jobs/sync_simple_table_job.rb +11 -32
- data/lib/canvas_sync/jobs/sync_submissions_job.rb +2 -4
- data/lib/canvas_sync/jobs/sync_terms_job.rb +25 -8
- data/lib/canvas_sync/misc_helper.rb +15 -0
- data/lib/canvas_sync/version.rb +1 -1
- data/spec/canvas_sync/canvas_sync_spec.rb +136 -153
- data/spec/canvas_sync/jobs/job_spec.rb +9 -17
- data/spec/canvas_sync/jobs/report_checker_spec.rb +1 -3
- data/spec/canvas_sync/jobs/report_processor_job_spec.rb +0 -3
- data/spec/canvas_sync/jobs/report_starter_spec.rb +19 -28
- data/spec/canvas_sync/jobs/sync_admins_job_spec.rb +1 -4
- data/spec/canvas_sync/jobs/sync_assignment_groups_job_spec.rb +2 -1
- data/spec/canvas_sync/jobs/sync_assignments_job_spec.rb +3 -2
- data/spec/canvas_sync/jobs/sync_context_module_items_job_spec.rb +3 -2
- data/spec/canvas_sync/jobs/sync_context_modules_job_spec.rb +3 -2
- data/spec/canvas_sync/jobs/sync_provisioning_report_job_spec.rb +3 -35
- data/spec/canvas_sync/jobs/sync_roles_job_spec.rb +1 -4
- data/spec/canvas_sync/jobs/sync_simple_table_job_spec.rb +5 -12
- data/spec/canvas_sync/jobs/sync_submissions_job_spec.rb +2 -1
- data/spec/canvas_sync/jobs/sync_terms_job_spec.rb +1 -4
- data/spec/dummy/app/models/account.rb +3 -0
- data/spec/dummy/app/models/pseudonym.rb +14 -0
- data/spec/dummy/app/models/submission.rb +1 -0
- data/spec/dummy/app/models/user.rb +1 -0
- data/spec/dummy/config/environments/test.rb +2 -0
- data/spec/dummy/db/migrate/20201016181346_create_pseudonyms.rb +24 -0
- data/spec/dummy/db/schema.rb +24 -4
- data/spec/job_batching/batch_aware_job_spec.rb +100 -0
- data/spec/job_batching/batch_spec.rb +363 -0
- data/spec/job_batching/callback_spec.rb +38 -0
- data/spec/job_batching/flow_spec.rb +91 -0
- data/spec/job_batching/integration/integration.rb +57 -0
- data/spec/job_batching/integration/nested.rb +88 -0
- data/spec/job_batching/integration/simple.rb +47 -0
- data/spec/job_batching/integration/workflow.rb +134 -0
- data/spec/job_batching/integration_helper.rb +48 -0
- data/spec/job_batching/sidekiq_spec.rb +124 -0
- data/spec/job_batching/status_spec.rb +92 -0
- data/spec/job_batching/support/base_job.rb +14 -0
- data/spec/job_batching/support/sample_callback.rb +2 -0
- data/spec/spec_helper.rb +17 -0
- metadata +90 -8
- data/lib/canvas_sync/job_chain.rb +0 -57
- data/lib/canvas_sync/jobs/fork_gather.rb +0 -59
- data/spec/canvas_sync/jobs/fork_gather_spec.rb +0 -73
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d7f0019fb32e5940971c4845d47a317bd4f451dec546a96a505e3162c8a120d4
|
4
|
+
data.tar.gz: 563d6fb7375f3576f8d2eac14752e14ebedbd210cc63b277c311d0e1c846da7e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce3550e2f0aa94df6c6b712776d605c16cac568f2a70d49ee668ce5ebdc0978654f01d63619d38bdb1a7befe670518210dbc1e847497fababa4428f779bfd775
|
7
|
+
data.tar.gz: 48a0e195407552a88b46ee93d7e8706585bd4729c618cdb807971a8694405c9e442b361da21472cf9c9d301bbc4dddb0c4c28b7faa5a8f3f4daf1a013195d6f3
|
data/README.md
CHANGED
@@ -91,27 +91,45 @@ This gem also helps with syncing and processing other reports if needed. In orde
|
|
91
91
|
- Integrate your reports with the `ReportStarter`
|
92
92
|
- Tell the gem what jobs to run
|
93
93
|
|
94
|
+
### `updated_after`
|
95
|
+
An `updated_after` param may be passed when triggering a provision or making a chain:
|
96
|
+
```ruby
|
97
|
+
CanvasSync.default_provisioning_report_chain(
|
98
|
+
%i[list of models to sync], updated_after: false
|
99
|
+
)
|
100
|
+
```
|
101
|
+
It may be one of the following values:
|
102
|
+
* `false` - Will not apply any `updated_after` filtering to the requested reports
|
103
|
+
* An ISO-8601 Date - Will pass the supplied date ad the `updated_after` param for the requested reports
|
104
|
+
* `true` (Default) - Will use the start date of the last successful sync
|
105
|
+
|
94
106
|
### Extensible chain
|
95
107
|
It is sometimes desired to extend or customize the chain of jobs that are run with CanvasSync.
|
96
108
|
This can be achieved with the following pattern:
|
97
109
|
|
98
110
|
```ruby
|
99
|
-
|
111
|
+
chain = CanvasSync.default_provisioning_report_chain(
|
100
112
|
%i[list of models to sync]
|
101
113
|
)
|
102
114
|
|
103
|
-
#
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
# Jobs placed before SyncProvisioningReportJob or after ForkGather will run once per Sync
|
109
|
-
job_chain[:jobs] << { job: CanvasSync::Jobs::ForkGather, options: {} }
|
115
|
+
# Add a custom job to the end of the chain.
|
116
|
+
chain << { job: CanvasSyncCompleteWorker, parameters: [{ job_id: job.id }] }
|
117
|
+
chain << { job: CanvasSyncCompleteWorker, options: { job_id: job.id } } # If an options key is provided, it will be automatically appended to the end of the :parameters array
|
118
|
+
|
119
|
+
chain.process!
|
110
120
|
|
111
|
-
#
|
112
|
-
|
121
|
+
# The chain object provides a fairly extensive API:
|
122
|
+
chain.insert({ job: SomeOtherJob }) # Adds the job to the end of the chain
|
123
|
+
chain.insert_at(0, { job: SomeOtherJob }) # Adds the job to the beginning of the chain
|
124
|
+
chain.insert({ job: SomeOtherJob }, after: 'CanvasSync::Jobs::SyncTermsJob') # Adds the job right after the SyncTermsJob
|
125
|
+
chain.insert({ job: SomeOtherJob }, before: 'CanvasSync::Jobs::SyncTermsJob') # Adds the job right before the SyncTermsJob
|
126
|
+
chain.insert({ job: SomeOtherJob }, with: 'CanvasSync::Jobs::SyncTermsJob') # Adds the job to be performed concurrently with the SyncTermsJob
|
113
127
|
|
114
|
-
|
128
|
+
# Some Jobs (such as the SyncTermsJob) have a sub-chain for, eg, Courses.
|
129
|
+
# chain.insert is aware of these sub-chains and will recurse into them when looking for a before:/after:/with: reference
|
130
|
+
chain.insert({ job: SomeOtherJob }, after: 'CanvasSync::Jobs::SyncCoursesJob') # Adds the job to be performed after SyncCoursesJob (which is a sub-job of the terms job and is duplicated for each term in the term_scope:)
|
131
|
+
# You can also retrieve the sub-chain like so:
|
132
|
+
chain.get_sub_chain('CanvasSync::Jobs::SyncTermsJob')
|
115
133
|
```
|
116
134
|
|
117
135
|
### Processor
|
@@ -134,9 +152,8 @@ Let's say we have a custom Canvas report called "my_really_cool_report_csv". Fir
|
|
134
152
|
|
135
153
|
```ruby
|
136
154
|
class MyReallyCoolReportJob < CanvasSync::Jobs::ReportStarter
|
137
|
-
def perform(
|
155
|
+
def perform(options)
|
138
156
|
super(
|
139
|
-
job_chain,
|
140
157
|
'my_really_cool_report_csv', # Report name
|
141
158
|
{ "parameters[param1]" => true }, # Report parameters
|
142
159
|
MyCoolProcessor.to_s, # Your processor class as a string
|
@@ -148,57 +165,6 @@ end
|
|
148
165
|
|
149
166
|
You can also see examples in `lib/canvas_sync/jobs/sync_users_job.rb` and `lib/canvas_sync/jobs/sync_provisioning_report.rb`.
|
150
167
|
|
151
|
-
### Start the jobs
|
152
|
-
|
153
|
-
The `CanvasSync.process_jobs` method allows you to pass in a chain of jobs to run. The job chain must be formatted like:
|
154
|
-
|
155
|
-
```ruby
|
156
|
-
{
|
157
|
-
jobs: [
|
158
|
-
{ job: JobClass, options: {} },
|
159
|
-
{ job: JobClass2, options: {} }
|
160
|
-
],
|
161
|
-
global_options: {}
|
162
|
-
}
|
163
|
-
```
|
164
|
-
|
165
|
-
Here is an example that runs our new report job first followed by the builtin provisioning job:
|
166
|
-
|
167
|
-
```ruby
|
168
|
-
job_chain = {
|
169
|
-
jobs: [
|
170
|
-
{ job: MyReallyCoolReportJob, options: {} },
|
171
|
-
{ job: CanvasSync::Jobs::SyncProvisioningReportJob, options: { models: ['users', 'courses'] } }
|
172
|
-
],
|
173
|
-
global_options: {}
|
174
|
-
}
|
175
|
-
|
176
|
-
CanvasSync.process_jobs(job_chain)
|
177
|
-
```
|
178
|
-
|
179
|
-
What if you've got some other job that you want run that doesn't deal with a report? No problem! Just make sure you call `CanvasSync.invoke_next` at the end of your job. Example:
|
180
|
-
|
181
|
-
|
182
|
-
```ruby
|
183
|
-
class SomeRandomJob < CanvasSync::Job
|
184
|
-
def perform(job_chain, options)
|
185
|
-
i_dunno_do_something!
|
186
|
-
|
187
|
-
CanvasSync.invoke_next(job_chain)
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
job_chain = {
|
192
|
-
jobs: [
|
193
|
-
{ job: SomeRandomJob, options: {} },
|
194
|
-
{ job: CanvasSync::Jobs::SyncProvisioningReportJob, options: { models: ['users', 'courses'] } }
|
195
|
-
],
|
196
|
-
global_options: {}
|
197
|
-
}
|
198
|
-
|
199
|
-
CanvasSync.process_jobs(job_chain)
|
200
|
-
```
|
201
|
-
|
202
168
|
### Batching
|
203
169
|
|
204
170
|
The provisioning report uses the `CanvasSync::Importers::BulkImporter` class to bulk import rows with the activerecord-import gem. It inserts rows in batches of 10,000 by default. This can be customized by setting the `BULK_IMPORTER_BATCH_SIZE` environment variable.
|
@@ -257,6 +223,14 @@ class CanvasSyncModel < ApplicationRecord
|
|
257
223
|
end
|
258
224
|
```
|
259
225
|
|
226
|
+
### Job Batching
|
227
|
+
CanvasSync adds a `CanvasSync::JobBatches` module. It adds Sidekiq/sidekiq-batch like support for Job Batches.
|
228
|
+
It integrates automatically with both Sidekiq and ActiveJob. The API is highly similar to the Sidekiq-batch implementation,
|
229
|
+
documentation for which can be found at https://github.com/mperham/sidekiq/wiki/Batches
|
230
|
+
|
231
|
+
A batch can be created using `Sidekiq::Batch` or `CanvasSync::JobBatching::Batch`.
|
232
|
+
|
233
|
+
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.
|
260
234
|
|
261
235
|
## Legacy Support
|
262
236
|
|
@@ -308,80 +282,19 @@ end
|
|
308
282
|
## Syncronize different reports
|
309
283
|
CanvasSync provides the functionality to import data from other reports into an specific table.
|
310
284
|
|
311
|
-
This can be
|
312
|
-
|
313
|
-
```ruby
|
314
|
-
CanvasSync.provisioning_sync(<array of models to sync>, term_scope: <optional term scope>)
|
315
|
-
CanvasSync
|
316
|
-
.simple_report_sync(
|
317
|
-
[
|
318
|
-
{
|
319
|
-
report_name: <report name>,
|
320
|
-
model: <model to sync>,
|
321
|
-
params: <hash with the require parameters the report needs to sync>
|
322
|
-
},
|
323
|
-
{
|
324
|
-
report_name: <report name>,
|
325
|
-
model: <model to sync>,
|
326
|
-
params: <hash with the require parameters the report needs to sync>
|
327
|
-
},
|
328
|
-
...
|
329
|
-
],
|
330
|
-
term_scope: <optional term scope>
|
331
|
-
)
|
332
|
-
```
|
333
|
-
|
334
|
-
Example:
|
285
|
+
This can be achieved by using the following method
|
335
286
|
|
336
287
|
```ruby
|
337
|
-
CanvasSync
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
},
|
348
|
-
{
|
349
|
-
report_name: 'proservices_provisioning_csv',
|
350
|
-
model: 'accounts',
|
351
|
-
params: {
|
352
|
-
"parameters[include_deleted]" => true,
|
353
|
-
"parameters[accounts]" => true
|
354
|
-
}
|
355
|
-
}
|
356
|
-
]
|
357
|
-
)
|
358
|
-
```
|
359
|
-
|
360
|
-
Example with the term_scope active:
|
361
|
-
|
362
|
-
```ruby
|
363
|
-
CanvasSync
|
364
|
-
.simple_report_sync(
|
365
|
-
[
|
366
|
-
{
|
367
|
-
report_name: 'proservices_provisioning_csv',
|
368
|
-
model: 'sections',
|
369
|
-
params: {
|
370
|
-
"parameters[include_deleted]" => true,
|
371
|
-
"parameters[sections]" => true
|
372
|
-
}
|
373
|
-
},
|
374
|
-
{
|
375
|
-
report_name: 'proservices_provisioning_csv',
|
376
|
-
model: 'courses',
|
377
|
-
params: {
|
378
|
-
"parameters[include_deleted]" => true,
|
379
|
-
"parameters[courses]" => true
|
380
|
-
}
|
381
|
-
}
|
382
|
-
],
|
383
|
-
term_scope: 'active'
|
384
|
-
)
|
288
|
+
chain = CanvasSync.default_provisioning_report_chain
|
289
|
+
chain << {
|
290
|
+
job: CanvasSync::Jobs::SyncSimpleTableJob,
|
291
|
+
options: {
|
292
|
+
report_name: <report name>,
|
293
|
+
model: <model to sync>,
|
294
|
+
params: <hash with the require parameters the report needs to sync>
|
295
|
+
},
|
296
|
+
}
|
297
|
+
chain.process!
|
385
298
|
```
|
386
299
|
|
387
300
|
## Configuration
|
@@ -421,7 +334,6 @@ class CanvasSyncStarterWorker
|
|
421
334
|
}
|
422
335
|
}
|
423
336
|
)
|
424
|
-
CanvasSync.invoke_next(job_chain)
|
425
337
|
end
|
426
338
|
|
427
339
|
def self.handle_canvas_sync_error(error, **options)
|
@@ -1,35 +1,16 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
t.text :job_arguments
|
1
|
+
class CreateCanvasSyncJobLog < CanvasSync::MiscHelper::MigrationClass
|
2
|
+
def change
|
3
|
+
create_table :canvas_sync_job_logs do |t|
|
4
|
+
t.datetime :started_at
|
5
|
+
t.datetime :completed_at
|
6
|
+
t.string :exception
|
7
|
+
t.text :backtrace
|
8
|
+
t.string :job_class
|
9
|
+
t.string :status
|
10
|
+
t.text :metadata
|
11
|
+
t.text :job_arguments
|
13
12
|
|
14
|
-
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
else
|
19
|
-
class CreateCanvasSyncJobLog < ActiveRecord::Migration
|
20
|
-
def change
|
21
|
-
create_table :canvas_sync_job_logs do |t|
|
22
|
-
t.datetime :started_at
|
23
|
-
t.datetime :completed_at
|
24
|
-
t.string :exception
|
25
|
-
t.text :backtrace
|
26
|
-
t.string :job_class
|
27
|
-
t.string :status
|
28
|
-
t.text :metadata
|
29
|
-
t.text :job_arguments
|
30
|
-
|
31
|
-
t.timestamps
|
32
|
-
end
|
13
|
+
t.timestamps
|
33
14
|
end
|
34
15
|
end
|
35
16
|
end
|
@@ -1,15 +1,6 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
add_index :canvas_sync_job_logs, :job_id
|
6
|
-
end
|
7
|
-
end
|
8
|
-
else
|
9
|
-
class AddJobIdToCanvasSyncJobLogs < ActiveRecord::Migration
|
10
|
-
def change
|
11
|
-
add_column :canvas_sync_job_logs, :job_id, :string
|
12
|
-
add_index :canvas_sync_job_logs, :job_id
|
13
|
-
end
|
1
|
+
class AddJobIdToCanvasSyncJobLogs < CanvasSync::MiscHelper::MigrationClass
|
2
|
+
def change
|
3
|
+
add_column :canvas_sync_job_logs, :job_id, :string
|
4
|
+
add_index :canvas_sync_job_logs, :job_id
|
14
5
|
end
|
15
6
|
end
|
@@ -1,13 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
add_column :canvas_sync_job_logs, :fork_count, :integer
|
5
|
-
end
|
6
|
-
end
|
7
|
-
else
|
8
|
-
class AddForkCountToCanvasSyncJobLogs < ActiveRecord::Migration
|
9
|
-
def change
|
10
|
-
add_column :canvas_sync_job_logs, :fork_count, :integer
|
11
|
-
end
|
1
|
+
class AddForkCountToCanvasSyncJobLogs < CanvasSync::MiscHelper::MigrationClass
|
2
|
+
def change
|
3
|
+
add_column :canvas_sync_job_logs, :fork_count, :integer
|
12
4
|
end
|
13
5
|
end
|
data/lib/canvas_sync.rb
CHANGED
@@ -2,9 +2,9 @@ require "bearcat"
|
|
2
2
|
|
3
3
|
require "canvas_sync/version"
|
4
4
|
require "canvas_sync/engine"
|
5
|
+
require "canvas_sync/misc_helper"
|
5
6
|
require "canvas_sync/class_callback_executor"
|
6
7
|
require "canvas_sync/job"
|
7
|
-
require "canvas_sync/job_chain"
|
8
8
|
require "canvas_sync/sidekiq_job"
|
9
9
|
require "canvas_sync/api_syncable"
|
10
10
|
require "canvas_sync/record"
|
@@ -13,6 +13,8 @@ require "canvas_sync/jobs/report_checker"
|
|
13
13
|
require "canvas_sync/jobs/report_processor_job"
|
14
14
|
require "canvas_sync/config"
|
15
15
|
|
16
|
+
require "canvas_sync/job_batches/batch"
|
17
|
+
|
16
18
|
Dir[File.dirname(__FILE__) + "/canvas_sync/jobs/*.rb"].each { |file| require file }
|
17
19
|
Dir[File.dirname(__FILE__) + "/canvas_sync/processors/*.rb"].each { |file| require file }
|
18
20
|
Dir[File.dirname(__FILE__) + "/canvas_sync/importers/*.rb"].each { |file| require file }
|
@@ -57,6 +59,9 @@ module CanvasSync
|
|
57
59
|
graded_submissions
|
58
60
|
].freeze
|
59
61
|
|
62
|
+
JobBatches::ChainBuilder.register_chain_job(CanvasSync::Jobs::SyncTermsJob, :sub_jobs)
|
63
|
+
JobBatches::ChainBuilder.register_chain_job(CanvasSync::Jobs::BeginSyncChainJob, 0)
|
64
|
+
|
60
65
|
class << self
|
61
66
|
# Runs a standard provisioning sync job with no extra report types.
|
62
67
|
# Terms will be synced first using the API. If you are syncing users/roles/admins
|
@@ -72,72 +77,9 @@ module CanvasSync
|
|
72
77
|
# and inserts it into the database. If an array of model names is provided then only those models will use legacy support.
|
73
78
|
# @param account_id [Integer, nil] This optional parameter can be used if your Term creation and
|
74
79
|
# canvas_sync_client methods require an account ID.
|
75
|
-
def provisioning_sync(models,
|
80
|
+
def provisioning_sync(models, **kwargs)
|
76
81
|
validate_models!(models)
|
77
|
-
|
78
|
-
end
|
79
|
-
|
80
|
-
# Runs a report different from provisioning sync job with no extra report types.
|
81
|
-
#
|
82
|
-
# @param reports_mapping [Array<Hash>] An Array of hash that list the model and params with their report you
|
83
|
-
# want to import:
|
84
|
-
# [{model: 'submissions', report_name: 'my_report_name_csv', params: { "parameters[include_deleted]" => true } }, ...]
|
85
|
-
# @param term_scope [Symbol, nil] An optional symbol representing a scope that exists on the Term model.
|
86
|
-
# The provisioning report will be run for each of the terms contained in that scope.
|
87
|
-
# @param account_id [Integer, nil] This optional parameter can be used if your Term creation and
|
88
|
-
# canvas_sync_client methods require an account ID.
|
89
|
-
def simple_report_sync(reports_mapping, term_scope: nil, account_id: nil)
|
90
|
-
invoke_next(simple_report_chain(reports_mapping, term_scope, account_id))
|
91
|
-
end
|
92
|
-
|
93
|
-
# Runs a chain of ordered jobs
|
94
|
-
#
|
95
|
-
# See the README for usage and examples
|
96
|
-
#
|
97
|
-
# @param job_chain [Hash]
|
98
|
-
def process_jobs(job_chain)
|
99
|
-
invoke_next(job_chain)
|
100
|
-
end
|
101
|
-
|
102
|
-
def duplicate_chain(job_chain)
|
103
|
-
Marshal.load(Marshal.dump(job_chain))
|
104
|
-
end
|
105
|
-
|
106
|
-
# Invokes the next job in a chain of jobs.
|
107
|
-
#
|
108
|
-
# This should typically be called automatically by the gem where necessary.
|
109
|
-
#
|
110
|
-
# @param job_chain [Hash] A chain of jobs to execute
|
111
|
-
def invoke_next(job_chain, extra_options: {})
|
112
|
-
job_chain = job_chain.chain_data if job_chain.is_a?(JobChain)
|
113
|
-
|
114
|
-
return if job_chain[:jobs].empty?
|
115
|
-
|
116
|
-
# Make sure all job classes are serialized as strings
|
117
|
-
job_chain[:jobs].each { |job| job[:job] = job[:job].to_s }
|
118
|
-
|
119
|
-
duped_job_chain = Marshal.load(Marshal.dump(job_chain))
|
120
|
-
jobs = duped_job_chain[:jobs]
|
121
|
-
next_job = jobs.shift
|
122
|
-
next_job_class = next_job[:job].constantize
|
123
|
-
next_options = next_job[:options] || {}
|
124
|
-
next_options.merge!(extra_options)
|
125
|
-
next_job_class.perform_later(duped_job_chain, next_options)
|
126
|
-
end
|
127
|
-
|
128
|
-
def fork(job_log, job_chain, keys: [])
|
129
|
-
job_chain = job_chain.chain_data if job_chain.is_a?(JobChain)
|
130
|
-
|
131
|
-
duped_job_chain = Marshal.load(Marshal.dump(job_chain))
|
132
|
-
duped_job_chain[:global_options][:fork_path] ||= []
|
133
|
-
duped_job_chain[:global_options][:fork_keys] ||= []
|
134
|
-
duped_job_chain[:global_options][:fork_path] << job_log.job_id
|
135
|
-
duped_job_chain[:global_options][:fork_keys] << ['canvas_term_id']
|
136
|
-
duped_job_chain[:global_options][:on_failure] ||= 'CanvasSync::Jobs::ForkGather.handle_branch_error'
|
137
|
-
sub_items = yield duped_job_chain
|
138
|
-
sub_count = sub_items.respond_to?(:count) ? sub_items.count : sub_items
|
139
|
-
job_log.fork_count = sub_count
|
140
|
-
sub_items
|
82
|
+
default_provisioning_report_chain(models, **kwargs).process!
|
141
83
|
end
|
142
84
|
|
143
85
|
# Given a Model or Relation, scope it down to items that should be synced
|
@@ -154,33 +96,6 @@ module CanvasSync
|
|
154
96
|
scope
|
155
97
|
end
|
156
98
|
|
157
|
-
# Syn any report to an specific set of models
|
158
|
-
#
|
159
|
-
# @param reports_mapping [Array<Hash>] List of reports with their specific model and params
|
160
|
-
# @param term_scope [String]
|
161
|
-
# @param account_id [Integer, nil] This optional parameter can be used if your Term creation and
|
162
|
-
# canvas_sync_client methods require an account ID.
|
163
|
-
def simple_report_chain(reports_mapping, term_scope=nil, account_id=nil)
|
164
|
-
jobs = reports_mapping.map do |report|
|
165
|
-
{
|
166
|
-
job: CanvasSync::Jobs::SyncSimpleTableJob.to_s,
|
167
|
-
options: {
|
168
|
-
report_name: report[:report_name],
|
169
|
-
model: report[:model],
|
170
|
-
mapping: report[:model],
|
171
|
-
klass: report[:model].singularize.capitalize.to_s,
|
172
|
-
term_scope: term_scope,
|
173
|
-
params: report[:params]
|
174
|
-
}
|
175
|
-
}
|
176
|
-
end
|
177
|
-
|
178
|
-
global_options = {}
|
179
|
-
global_options[:account_id] = account_id if account_id.present?
|
180
|
-
|
181
|
-
JobChain.new(jobs: jobs, global_options: global_options)
|
182
|
-
end
|
183
|
-
|
184
99
|
# Syncs terms, users/roles/admins if necessary, then the rest of the specified models.
|
185
100
|
#
|
186
101
|
# @param models [Array<String>]
|
@@ -191,7 +106,7 @@ module CanvasSync
|
|
191
106
|
# @param account_id [Integer, nil] This optional parameter can be used if your Term creation and
|
192
107
|
# canvas_sync_client methods require an account ID.
|
193
108
|
# @return [Hash]
|
194
|
-
def default_provisioning_report_chain(models, term_scope
|
109
|
+
def default_provisioning_report_chain(models, term_scope: nil, legacy_support: false, account_id: nil, updated_after: nil, options: {}) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/LineLength
|
195
110
|
return unless models.present?
|
196
111
|
models.map! &:to_s
|
197
112
|
term_scope = term_scope.to_s if term_scope
|
@@ -210,64 +125,67 @@ module CanvasSync
|
|
210
125
|
context_module_items: CanvasSync::Jobs::SyncContextModuleItemsJob,
|
211
126
|
}.with_indifferent_access
|
212
127
|
|
213
|
-
|
128
|
+
root_chain = JobBatches::ChainBuilder.new(CanvasSync::Jobs::BeginSyncChainJob)
|
129
|
+
concurrent_root_chain = JobBatches::ChainBuilder.new(JobBatches::ConcurrentBatchJob)
|
130
|
+
root_chain << concurrent_root_chain
|
131
|
+
current_chain = concurrent_root_chain
|
132
|
+
|
214
133
|
try_add_model_job = ->(model) {
|
215
134
|
return unless models.include?(model)
|
216
|
-
|
135
|
+
current_chain << { job: model_job_map[model].to_s, options: options[model.to_sym] || {} }
|
217
136
|
models -= [model]
|
218
137
|
}
|
219
138
|
|
220
139
|
##############################
|
221
|
-
#
|
140
|
+
# General provisioning jobs (not term-scoped)
|
222
141
|
##############################
|
223
142
|
|
224
|
-
#
|
225
|
-
models
|
226
|
-
try_add_model_job.call('terms')
|
143
|
+
# Terms are always synced regardless of the models option
|
144
|
+
models -= ['terms']
|
227
145
|
|
228
|
-
# Accounts, users, roles, and admins
|
146
|
+
# Accounts, users, roles, and admins cannot be scoped to term
|
229
147
|
try_add_model_job.call('accounts')
|
230
148
|
|
231
149
|
# These Models use the provisioning report, but are not term-scoped,
|
232
|
-
# so we sync them
|
150
|
+
# so we sync them outside of the term scoping to ensure work is not duplicated
|
233
151
|
if term_scope.present?
|
234
152
|
models -= (first_provisioning_models = models & ['users', 'pseudonyms'])
|
235
|
-
|
236
|
-
generate_provisioning_jobs(first_provisioning_models, options)
|
237
|
-
)
|
153
|
+
current_chain.insert(generate_provisioning_jobs(first_provisioning_models, options))
|
238
154
|
end
|
239
155
|
|
240
156
|
try_add_model_job.call('roles')
|
241
157
|
try_add_model_job.call('admins')
|
242
|
-
pre_provisioning_jobs = jobs
|
243
158
|
|
244
159
|
###############################
|
245
|
-
#
|
160
|
+
# Per-term provisioning jobs
|
246
161
|
###############################
|
247
162
|
|
248
|
-
|
163
|
+
per_term_chain = JobBatches::ChainBuilder.new(model_job_map[:terms])
|
164
|
+
per_term_chain.params[:term_scope] = term_scope
|
165
|
+
current_chain << per_term_chain
|
166
|
+
current_chain = per_term_chain
|
167
|
+
|
249
168
|
try_add_model_job.call('assignments')
|
250
169
|
try_add_model_job.call('submissions')
|
251
170
|
try_add_model_job.call('assignment_groups')
|
252
171
|
try_add_model_job.call('context_modules')
|
253
172
|
try_add_model_job.call('context_module_items')
|
254
|
-
|
173
|
+
|
174
|
+
current_chain.insert(
|
175
|
+
generate_provisioning_jobs(models, options, only_split: ['users'])
|
176
|
+
)
|
255
177
|
|
256
178
|
###############################
|
257
|
-
#
|
179
|
+
# Wrap it all up
|
258
180
|
###############################
|
259
181
|
|
260
|
-
|
261
|
-
*pre_provisioning_jobs,
|
262
|
-
*generate_provisioning_jobs(models, options, job_options: { term_scope: term_scope }, only_split: ['users']),
|
263
|
-
*post_provisioning_jobs,
|
264
|
-
]
|
265
|
-
|
266
|
-
global_options = { legacy_support: legacy_support }
|
182
|
+
global_options = { legacy_support: legacy_support, updated_after: updated_after }
|
267
183
|
global_options[:account_id] = account_id if account_id.present?
|
268
184
|
global_options.merge!(options[:global]) if options[:global].present?
|
269
185
|
|
270
|
-
|
186
|
+
root_chain.params[1] = global_options
|
187
|
+
|
188
|
+
root_chain
|
271
189
|
end
|
272
190
|
|
273
191
|
def group_by_job_options(model_list, options_hash, only_split: nil, default_key: :provisioning)
|