canvas_sync 0.10.4 → 0.10.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +25 -2
- data/db/migrate/20190916154829_add_fork_count_to_canvas_sync_job_logs.rb +13 -0
- data/lib/canvas_sync.rb +13 -0
- data/lib/canvas_sync/jobs/fork_gather.rb +26 -0
- data/lib/canvas_sync/jobs/sync_provisioning_report_job.rb +17 -7
- data/lib/canvas_sync/jobs/sync_simple_table_job.rb +17 -7
- data/lib/canvas_sync/version.rb +1 -1
- data/spec/canvas_sync/jobs/fork_gather_spec.rb +30 -0
- data/spec/canvas_sync/jobs/sync_provisioning_report_job_spec.rb +3 -0
- data/spec/canvas_sync/jobs/sync_simple_table_job_spec.rb +1 -0
- data/spec/dummy/db/schema.rb +2 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f1cc1054e379b920c5acee75583700fdffaae885a4cea48df1d8de97ed70c02e
|
4
|
+
data.tar.gz: 83741af3ec47ee4b72db5e4a354a8713c002fc6930cfe352a80c5f57a36dba4a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dc7ad8ad007bda5edb7cf980b767113075a4be84cf1c2a228cf8287f8aba2c587bb170574a0168216b0bcaa19c8c395224d37249954b23203a50df234e5d9599
|
7
|
+
data.tar.gz: be307cba8401af1b7697d4c843d260e290517aca0f3d3866a72db6f327f6d3726df894a5306f2b39f2e10eacbb22465a45b5b8398c810304d53145ef59a17ad7
|
data/README.md
CHANGED
@@ -91,6 +91,29 @@ 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
|
+
### Extensible chain
|
95
|
+
It is sometimes desired to extend or customize the chain of jobs that are run with CanvasSync.
|
96
|
+
This can be achieved with the following pattern:
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
job_chain = CanvasSync.default_provisioning_report_chain(
|
100
|
+
%i[list of models to sync]
|
101
|
+
)
|
102
|
+
|
103
|
+
# CanvasSync forks the chain for each term within a term scope. The ForkGather Job can be used to unfork the chain.
|
104
|
+
# For example multiple Terms are in the term_scope. CanvasSync syncs Accounts, Terms, and Users (if enabled) and then
|
105
|
+
# forks the chain to sync other models (eg Course, Sections, etc.) per-Term.
|
106
|
+
# ForkGather will wait until all the forked chains are complete before continuing.
|
107
|
+
# TL;DR: Jobs placed after SyncProvisioningReportJob and before ForkGather will run once per Term per Sync;
|
108
|
+
# Jobs placed before SyncProvisioningReportJob or after ForkGather will run once per Sync
|
109
|
+
job_chain[:jobs] << { job: CanvasSync::Jobs::ForkGather, options: {} }
|
110
|
+
|
111
|
+
# Add a custom job to the end of the chain. Custom jobs must accept 2 arguments (job_chain, options) and call CanvasSync.invoke_next(job_chain) when complete
|
112
|
+
job_chain[:jobs] << { job: CanvasSyncCompleteWorker, options: { job_id: job.id } }
|
113
|
+
|
114
|
+
CanvasSync.invoke_next(job_chain)
|
115
|
+
```
|
116
|
+
|
94
117
|
### Processor
|
95
118
|
|
96
119
|
Your processor class must implement a `process` class method that receives a `report_file_path` and a hash of `options`. (See the `CanvasSync::Processors::ProvisioningReportProcessor` for an example.) The gem handles the work of enqueueing and downloading the report and then passes the file path to your class to process as needed. A simple example might be:
|
@@ -141,7 +164,7 @@ The `CanvasSync.process_jobs` method allows you to pass in a chain of jobs to ru
|
|
141
164
|
|
142
165
|
Here is an example that runs our new report job first followed by the builtin provisioning job:
|
143
166
|
|
144
|
-
```
|
167
|
+
```ruby
|
145
168
|
job_chain = {
|
146
169
|
jobs: [
|
147
170
|
{ job: MyReallyCoolReportJob, options: {} },
|
@@ -156,7 +179,7 @@ CanvasSync.process_jobs(job_chain)
|
|
156
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:
|
157
180
|
|
158
181
|
|
159
|
-
```
|
182
|
+
```ruby
|
160
183
|
class SomeRandomJob < CanvasSync::Job
|
161
184
|
def perform(job_chain, options)
|
162
185
|
i_dunno_do_something!
|
@@ -0,0 +1,13 @@
|
|
1
|
+
if Rails.version.to_f >= 5.0
|
2
|
+
class AddForkCountToCanvasSyncJobLogs < ActiveRecord::Migration[Rails.version.to_f]
|
3
|
+
def change
|
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
|
12
|
+
end
|
13
|
+
end
|
data/lib/canvas_sync.rb
CHANGED
@@ -6,6 +6,7 @@ require "canvas_sync/sidekiq_job"
|
|
6
6
|
require "canvas_sync/api_syncable"
|
7
7
|
require "canvas_sync/jobs/report_starter"
|
8
8
|
require "canvas_sync/jobs/report_checker"
|
9
|
+
require "canvas_sync/jobs/fork_gather"
|
9
10
|
require "canvas_sync/jobs/report_processor_job"
|
10
11
|
require "canvas_sync/jobs/sync_provisioning_report_job"
|
11
12
|
require "canvas_sync/jobs/sync_simple_table_job.rb"
|
@@ -118,6 +119,18 @@ module CanvasSync
|
|
118
119
|
next_job_class.perform_later(duped_job_chain, next_job[:options])
|
119
120
|
end
|
120
121
|
|
122
|
+
def fork(job_log, job_chain, keys: [])
|
123
|
+
duped_job_chain = Marshal.load(Marshal.dump(job_chain))
|
124
|
+
duped_job_chain[:global_options][:fork_path] ||= []
|
125
|
+
duped_job_chain[:global_options][:fork_keys] ||= []
|
126
|
+
duped_job_chain[:global_options][:fork_path] << job_log.job_id
|
127
|
+
duped_job_chain[:global_options][:fork_keys] << ['canvas_term_id']
|
128
|
+
sub_items = yield duped_job_chain
|
129
|
+
sub_count = sub_items.respond_to?(:count) ? sub_items.count : sub_items
|
130
|
+
job_log.update!(fork_count: sub_count)
|
131
|
+
sub_items
|
132
|
+
end
|
133
|
+
|
121
134
|
# Syn any report to an specific set of models
|
122
135
|
#
|
123
136
|
# @param reports_mapping [Array<Hash>] List of reports with their specific model and params
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module CanvasSync
|
2
|
+
module Jobs
|
3
|
+
class ForkGather < CanvasSync::Job
|
4
|
+
def perform(job_chain, options)
|
5
|
+
fork_item = (job_chain[:global_options][:fork_path] || []).pop
|
6
|
+
|
7
|
+
if fork_item.present?
|
8
|
+
forked_job = CanvasSync::JobLog.find_by(job_id: fork_item)
|
9
|
+
forked_job.with_lock do
|
10
|
+
forked_job.fork_count -= 1
|
11
|
+
forked_job.save!
|
12
|
+
end
|
13
|
+
|
14
|
+
if forked_job.fork_count <= 0
|
15
|
+
(job_chain[:global_options][:fork_keys] || []).pop&.each do |k|
|
16
|
+
job_chain[:global_options].delete(k.to_sym)
|
17
|
+
end
|
18
|
+
CanvasSync.invoke_next(job_chain)
|
19
|
+
end
|
20
|
+
else
|
21
|
+
CanvasSync.invoke_next(job_chain)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -8,13 +8,23 @@ module CanvasSync
|
|
8
8
|
# models to sync.
|
9
9
|
def perform(job_chain, options)
|
10
10
|
if options[:term_scope]
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
11
|
+
sub_reports = CanvasSync.fork(@job_log, job_chain, keys: [:canvas_term_id]) do |job_chain|
|
12
|
+
Term.send(options[:term_scope]).find_each.map do |term|
|
13
|
+
# Deep copy the job_chain so each report gets the correct term id passed into
|
14
|
+
# its options with no side effects
|
15
|
+
term_id = get_term_id(term)
|
16
|
+
duped_job_chain = Marshal.load(Marshal.dump(job_chain))
|
17
|
+
duped_job_chain[:global_options][:canvas_term_id] = term_id
|
18
|
+
{
|
19
|
+
job_chain: duped_job_chain,
|
20
|
+
params: report_params(options, term_id),
|
21
|
+
options: options,
|
22
|
+
}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
sub_reports.each do |r|
|
27
|
+
start_report(r[:params], r[:job_chain], r[:options])
|
18
28
|
end
|
19
29
|
else
|
20
30
|
start_report(report_params(options), job_chain, options)
|
@@ -9,13 +9,23 @@ module CanvasSync
|
|
9
9
|
# @param options [Hash]
|
10
10
|
def perform(job_chain, options)
|
11
11
|
if options[:term_scope]
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
12
|
+
sub_reports = CanvasSync.fork(@job_log, job_chain, keys: [:canvas_term_id]) do |job_chain|
|
13
|
+
Term.send(options[:term_scope]).find_each.map do |term|
|
14
|
+
# Deep copy the job_chain so each report gets the correct term id passed into
|
15
|
+
# its options with no side effects
|
16
|
+
term_id = get_term_id(term)
|
17
|
+
duped_job_chain = Marshal.load(Marshal.dump(job_chain))
|
18
|
+
duped_job_chain[:global_options][:canvas_term_id] = term_id
|
19
|
+
{
|
20
|
+
job_chain: duped_job_chain,
|
21
|
+
params: report_params(options, term_id),
|
22
|
+
options: options,
|
23
|
+
}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
sub_reports.each do |r|
|
28
|
+
start_report(r[:params], r[:job_chain], r[:options])
|
19
29
|
end
|
20
30
|
else
|
21
31
|
start_report(report_params(options), job_chain, options)
|
data/lib/canvas_sync/version.rb
CHANGED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe CanvasSync::Jobs::ForkGather do
|
4
|
+
describe '#perform' do
|
5
|
+
let!(:job_log) { CanvasSync::JobLog.create!(job_id: 'BLAH', fork_count: 3) }
|
6
|
+
let(:job_chain) { {jobs: [], global_options: { fork_path: ['BLAH'] }} }
|
7
|
+
|
8
|
+
it 'decrements fork_count' do
|
9
|
+
CanvasSync::Jobs::ForkGather.perform_now(job_chain, {})
|
10
|
+
expect(job_log.reload.fork_count).to eq 2
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'does not continue chain if fork_count > 0' do
|
14
|
+
expect(CanvasSync).not_to receive(:invoke_next)
|
15
|
+
CanvasSync::Jobs::ForkGather.perform_now(job_chain, {})
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'continues the chain if fork_count <= 0' do
|
19
|
+
job_log.update!(fork_count: 1)
|
20
|
+
expect(CanvasSync).to receive(:invoke_next)
|
21
|
+
CanvasSync::Jobs::ForkGather.perform_now(job_chain, {})
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'continues if no fork_path is specified' do
|
25
|
+
job_chain[:global_options].delete(:fork_path)
|
26
|
+
expect(CanvasSync).to receive(:invoke_next)
|
27
|
+
CanvasSync::Jobs::ForkGather.perform_now(job_chain, {})
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -12,6 +12,7 @@ RSpec.describe CanvasSync::Jobs::SyncProvisioningReportJob do
|
|
12
12
|
it 'enqueues a ReportStarter for a provisioning report for the specified models for each term' do
|
13
13
|
expected_job_chain = Marshal.load(Marshal.dump(job_chain))
|
14
14
|
expected_job_chain[:global_options][:canvas_term_id] = active_term_1.canvas_id
|
15
|
+
expected_job_chain[:global_options] = hash_including(expected_job_chain[:global_options])
|
15
16
|
|
16
17
|
expect(CanvasSync::Jobs::ReportStarter).to receive(:perform_later)
|
17
18
|
.with(
|
@@ -31,6 +32,7 @@ RSpec.describe CanvasSync::Jobs::SyncProvisioningReportJob do
|
|
31
32
|
|
32
33
|
expected_job_chain_2 = Marshal.load(Marshal.dump(job_chain))
|
33
34
|
expected_job_chain_2[:global_options][:canvas_term_id] = active_term_2.canvas_id
|
35
|
+
expected_job_chain_2[:global_options] = hash_including(expected_job_chain_2[:global_options])
|
34
36
|
|
35
37
|
expect(CanvasSync::Jobs::ReportStarter).to receive(:perform_later)
|
36
38
|
.with(
|
@@ -52,6 +54,7 @@ RSpec.describe CanvasSync::Jobs::SyncProvisioningReportJob do
|
|
52
54
|
job_chain,
|
53
55
|
{ models: ['users', 'courses'], term_scope: 'active' }
|
54
56
|
)
|
57
|
+
expect(CanvasSync::JobLog.last.fork_count).to eq 2
|
55
58
|
end
|
56
59
|
end
|
57
60
|
|
@@ -11,6 +11,7 @@ RSpec.describe CanvasSync::Jobs::SyncSimpleTableJob do
|
|
11
11
|
it 'enqueues a ReportStarter for a provisioning report for the specified model for a term' do
|
12
12
|
expected_job_chain = Marshal.load(Marshal.dump(job_chain))
|
13
13
|
expected_job_chain[:global_options][:canvas_term_id] = active_term_1.canvas_id
|
14
|
+
expected_job_chain[:global_options] = hash_including(expected_job_chain[:global_options])
|
14
15
|
|
15
16
|
expect(CanvasSync::Jobs::ReportStarter).to receive(:perform_later)
|
16
17
|
.with(
|
data/spec/dummy/db/schema.rb
CHANGED
@@ -10,7 +10,7 @@
|
|
10
10
|
#
|
11
11
|
# It's strongly recommended that you check this file into your version control system.
|
12
12
|
|
13
|
-
ActiveRecord::Schema.define(version:
|
13
|
+
ActiveRecord::Schema.define(version: 20190916154829) do
|
14
14
|
|
15
15
|
# These are extensions that must be enabled in order to support this database
|
16
16
|
enable_extension "plpgsql"
|
@@ -92,6 +92,7 @@ ActiveRecord::Schema.define(version: 20190702203632) do
|
|
92
92
|
t.datetime "created_at", null: false
|
93
93
|
t.datetime "updated_at", null: false
|
94
94
|
t.string "job_id"
|
95
|
+
t.integer "fork_count"
|
95
96
|
t.index ["job_id"], name: "index_canvas_sync_job_logs_on_job_id"
|
96
97
|
end
|
97
98
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: canvas_sync
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.10.
|
4
|
+
version: 0.10.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nate Collings
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-09-
|
11
|
+
date: 2019-09-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -319,6 +319,7 @@ files:
|
|
319
319
|
- config/initializers/apartment.rb
|
320
320
|
- db/migrate/20170915210836_create_canvas_sync_job_log.rb
|
321
321
|
- db/migrate/20180725155729_add_job_id_to_canvas_sync_job_logs.rb
|
322
|
+
- db/migrate/20190916154829_add_fork_count_to_canvas_sync_job_logs.rb
|
322
323
|
- lib/canvas_sync.rb
|
323
324
|
- lib/canvas_sync/api_syncable.rb
|
324
325
|
- lib/canvas_sync/config.rb
|
@@ -366,6 +367,7 @@ files:
|
|
366
367
|
- lib/canvas_sync/importers/bulk_importer.rb
|
367
368
|
- lib/canvas_sync/importers/legacy_importer.rb
|
368
369
|
- lib/canvas_sync/job.rb
|
370
|
+
- lib/canvas_sync/jobs/fork_gather.rb
|
369
371
|
- lib/canvas_sync/jobs/report_checker.rb
|
370
372
|
- lib/canvas_sync/jobs/report_processor_job.rb
|
371
373
|
- lib/canvas_sync/jobs/report_starter.rb
|
@@ -392,6 +394,7 @@ files:
|
|
392
394
|
- lib/canvas_sync/sidekiq_job.rb
|
393
395
|
- lib/canvas_sync/version.rb
|
394
396
|
- spec/canvas_sync/canvas_sync_spec.rb
|
397
|
+
- spec/canvas_sync/jobs/fork_gather_spec.rb
|
395
398
|
- spec/canvas_sync/jobs/job_spec.rb
|
396
399
|
- spec/canvas_sync/jobs/report_checker_spec.rb
|
397
400
|
- spec/canvas_sync/jobs/report_processor_job_spec.rb
|
@@ -562,6 +565,7 @@ specification_version: 4
|
|
562
565
|
summary: Gem for generating Canvas models and migrations and syncing data from Canvas
|
563
566
|
test_files:
|
564
567
|
- spec/canvas_sync/canvas_sync_spec.rb
|
568
|
+
- spec/canvas_sync/jobs/fork_gather_spec.rb
|
565
569
|
- spec/canvas_sync/jobs/job_spec.rb
|
566
570
|
- spec/canvas_sync/jobs/report_checker_spec.rb
|
567
571
|
- spec/canvas_sync/jobs/report_processor_job_spec.rb
|