canvas_sync 0.16.5 → 0.17.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.
Files changed (80) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +49 -137
  3. data/app/models/canvas_sync/sync_batch.rb +5 -0
  4. data/db/migrate/20201018210836_create_canvas_sync_sync_batches.rb +11 -0
  5. data/lib/canvas_sync/importers/bulk_importer.rb +4 -7
  6. data/lib/canvas_sync/job.rb +4 -10
  7. data/lib/canvas_sync/job_batches/batch.rb +399 -0
  8. data/lib/canvas_sync/job_batches/batch_aware_job.rb +62 -0
  9. data/lib/canvas_sync/job_batches/callback.rb +153 -0
  10. data/lib/canvas_sync/job_batches/chain_builder.rb +203 -0
  11. data/lib/canvas_sync/job_batches/context_hash.rb +147 -0
  12. data/lib/canvas_sync/job_batches/jobs/base_job.rb +7 -0
  13. data/lib/canvas_sync/job_batches/jobs/concurrent_batch_job.rb +18 -0
  14. data/lib/canvas_sync/job_batches/jobs/serial_batch_job.rb +73 -0
  15. data/lib/canvas_sync/job_batches/sidekiq.rb +91 -0
  16. data/lib/canvas_sync/job_batches/status.rb +63 -0
  17. data/lib/canvas_sync/jobs/begin_sync_chain_job.rb +34 -0
  18. data/lib/canvas_sync/jobs/report_checker.rb +3 -6
  19. data/lib/canvas_sync/jobs/report_processor_job.rb +2 -5
  20. data/lib/canvas_sync/jobs/report_starter.rb +28 -20
  21. data/lib/canvas_sync/jobs/sync_accounts_job.rb +3 -5
  22. data/lib/canvas_sync/jobs/sync_admins_job.rb +2 -4
  23. data/lib/canvas_sync/jobs/sync_assignment_groups_job.rb +2 -4
  24. data/lib/canvas_sync/jobs/sync_assignments_job.rb +2 -4
  25. data/lib/canvas_sync/jobs/sync_context_module_items_job.rb +2 -4
  26. data/lib/canvas_sync/jobs/sync_context_modules_job.rb +2 -4
  27. data/lib/canvas_sync/jobs/sync_provisioning_report_job.rb +4 -31
  28. data/lib/canvas_sync/jobs/sync_roles_job.rb +2 -5
  29. data/lib/canvas_sync/jobs/sync_simple_table_job.rb +11 -32
  30. data/lib/canvas_sync/jobs/sync_submissions_job.rb +2 -4
  31. data/lib/canvas_sync/jobs/sync_terms_job.rb +22 -7
  32. data/lib/canvas_sync/processors/assignment_groups_processor.rb +2 -3
  33. data/lib/canvas_sync/processors/assignments_processor.rb +2 -3
  34. data/lib/canvas_sync/processors/context_module_items_processor.rb +2 -3
  35. data/lib/canvas_sync/processors/context_modules_processor.rb +2 -3
  36. data/lib/canvas_sync/processors/normal_processor.rb +1 -2
  37. data/lib/canvas_sync/processors/provisioning_report_processor.rb +2 -10
  38. data/lib/canvas_sync/processors/submissions_processor.rb +2 -3
  39. data/lib/canvas_sync/version.rb +1 -1
  40. data/lib/canvas_sync.rb +34 -97
  41. data/spec/canvas_sync/canvas_sync_spec.rb +126 -153
  42. data/spec/canvas_sync/jobs/job_spec.rb +9 -17
  43. data/spec/canvas_sync/jobs/report_checker_spec.rb +1 -3
  44. data/spec/canvas_sync/jobs/report_processor_job_spec.rb +0 -3
  45. data/spec/canvas_sync/jobs/report_starter_spec.rb +19 -28
  46. data/spec/canvas_sync/jobs/sync_admins_job_spec.rb +1 -4
  47. data/spec/canvas_sync/jobs/sync_assignment_groups_job_spec.rb +2 -1
  48. data/spec/canvas_sync/jobs/sync_assignments_job_spec.rb +3 -2
  49. data/spec/canvas_sync/jobs/sync_context_module_items_job_spec.rb +3 -2
  50. data/spec/canvas_sync/jobs/sync_context_modules_job_spec.rb +3 -2
  51. data/spec/canvas_sync/jobs/sync_provisioning_report_job_spec.rb +3 -35
  52. data/spec/canvas_sync/jobs/sync_roles_job_spec.rb +1 -4
  53. data/spec/canvas_sync/jobs/sync_simple_table_job_spec.rb +5 -12
  54. data/spec/canvas_sync/jobs/sync_submissions_job_spec.rb +2 -1
  55. data/spec/canvas_sync/jobs/sync_terms_job_spec.rb +1 -4
  56. data/spec/dummy/config/environments/test.rb +2 -0
  57. data/spec/dummy/db/schema.rb +9 -1
  58. data/spec/job_batching/batch_aware_job_spec.rb +100 -0
  59. data/spec/job_batching/batch_spec.rb +363 -0
  60. data/spec/job_batching/callback_spec.rb +38 -0
  61. data/spec/job_batching/flow_spec.rb +91 -0
  62. data/spec/job_batching/integration/integration.rb +57 -0
  63. data/spec/job_batching/integration/nested.rb +88 -0
  64. data/spec/job_batching/integration/simple.rb +47 -0
  65. data/spec/job_batching/integration/workflow.rb +134 -0
  66. data/spec/job_batching/integration_helper.rb +48 -0
  67. data/spec/job_batching/sidekiq_spec.rb +124 -0
  68. data/spec/job_batching/status_spec.rb +92 -0
  69. data/spec/job_batching/support/base_job.rb +14 -0
  70. data/spec/job_batching/support/sample_callback.rb +2 -0
  71. data/spec/spec_helper.rb +10 -0
  72. metadata +91 -23
  73. data/lib/canvas_sync/job_chain.rb +0 -102
  74. data/lib/canvas_sync/jobs/fork_gather.rb +0 -74
  75. data/spec/canvas_sync/jobs/fork_gather_spec.rb +0 -73
  76. data/spec/dummy/db/test.sqlite3 +0 -0
  77. data/spec/dummy/log/development.log +0 -1248
  78. data/spec/dummy/log/test.log +0 -43258
  79. data/spec/support/fixtures/reports/provisioning_csv_unzipped/courses.csv +0 -3
  80. data/spec/support/fixtures/reports/provisioning_csv_unzipped/users.csv +0 -4
@@ -1,102 +0,0 @@
1
- module CanvasSync
2
- class JobChain
3
- attr_reader :chain_data
4
-
5
- delegate_missing_to :chain_data
6
-
7
- VALID_PLACEMENT_PARAMETERS = %i[before after].freeze
8
-
9
- def initialize(chain_data)
10
- @chain_data = chain_data
11
- end
12
-
13
- def jobs
14
- chain_data[:jobs]
15
- end
16
-
17
- def global_options
18
- chain_data[:global_options]
19
- end
20
-
21
- def merge_options(job, options)
22
- jobs.each do |j|
23
- j[:options].deep_merge!(options) if job_matches_pattern(j, job)
24
- end
25
- end
26
-
27
- def insert(new_job, **kwargs)
28
- invalid_params = kwargs.keys - VALID_PLACEMENT_PARAMETERS
29
- raise "Invalid placement parameters: #{invalid_params.map(&:to_s).join(', ')}" if invalid_params.present?
30
- raise "Exactly one placement parameter may be provided" if kwargs.values.compact!.length > 1
31
-
32
- if !kwargs.present?
33
- jobs << new_job
34
- else
35
- placement = kwargs.keys[0]
36
- relative_to = kwargs.values[0]
37
-
38
- index = jobs.index { |job| job_matches_pattern(job, relative_to) }
39
- raise "Could not find a \"#{relative_to}\" job in the chain" if index.nil?
40
-
41
- index += 1 if placement == :after
42
- new_job[:job] = new_job[:job].to_s
43
- jobs.insert(index, new_job)
44
- end
45
- end
46
-
47
- def process!(extra_options: {})
48
- perform_next(extra_options)
49
- end
50
-
51
- def duplicate
52
- self.class.new(Marshal.load(Marshal.dump(chain_data)))
53
- end
54
-
55
- def normalize!
56
- @chain_data[:global_options] ||= {}
57
- end
58
-
59
- def serialize
60
- normalize!
61
- chain_data
62
- end
63
-
64
- def perform_next(extra_options = {})
65
- return if jobs.empty?
66
-
67
- # Make sure all job classes are serialized as strings
68
- jobs.each { |job| job[:job] = job[:job].to_s }
69
-
70
- duped_job_chain = duplicate
71
-
72
- jobs = duped_job_chain[:jobs]
73
- next_job = jobs.shift
74
- next_job_class = next_job[:job].constantize
75
- next_options = next_job[:options] || {}
76
- next_options.merge!(extra_options)
77
- next_job_class.perform_later(duped_job_chain.serialize, next_options)
78
- end
79
-
80
- def fork(job_log, keys: [])
81
- duped_job_chain = duplicate
82
- duped_job_chain[:fork_state] ||= {}
83
- duped_job_chain[:fork_state][:forking_path] ||= []
84
- duped_job_chain[:fork_state][:pre_fork_globals] ||= []
85
-
86
- duped_job_chain[:fork_state][:forking_path] << job_log.job_id
87
- duped_job_chain[:fork_state][:pre_fork_globals] << global_options
88
- # duped_job_chain[:global_options][:on_failure] ||= ['CanvasSync::Jobs::ForkGather.handle_branch_error']
89
-
90
- sub_items = yield duped_job_chain
91
- sub_count = sub_items.respond_to?(:count) ? sub_items.count : sub_items
92
- job_log.update!(fork_count: sub_count)
93
- sub_items
94
- end
95
-
96
- private
97
-
98
- def job_matches_pattern(job_entry, pattern)
99
- job_entry[:job].to_s == pattern.to_s
100
- end
101
- end
102
- end
@@ -1,74 +0,0 @@
1
- module CanvasSync
2
- module Jobs
3
- class ForkGather < CanvasSync::Job
4
- def perform(job_chain, options)
5
- forked_job = self.class.forked_at_job(job_chain)
6
-
7
- while true
8
- if forked_job.present?
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
- pfgs = job_chain[:fork_state][:pre_fork_globals].pop
16
- job_chain[:global_options] = pfgs
17
-
18
- if options[:gather_all]
19
- # If we want to gather all, repeat for the next level fork
20
- forked_job = self.class.forked_at_job(job_chain)
21
- else
22
- forked_job = nil
23
- end
24
- else
25
- # If a fork was found and it isn't complete, break the loop before continuing the chain
26
- break
27
- end
28
-
29
- # Repeat this logic for [if gather_all] the next fork up, or [if not gather_all] nil
30
- next
31
- end
32
-
33
- # If there is no current fork (either not in a fork, or all forks were closed), continue the chain
34
- CanvasSync.invoke_next(job_chain)
35
- break
36
- end
37
- end
38
-
39
- def self.handle_branch_error(e, job_chain:, skip_invoke: false, **kwargs)
40
- return nil unless job_chain&.dig(:fork_state, :forking_path).present?
41
-
42
- duped_chain = CanvasSync.duplicate_chain(job_chain)
43
- job_list = duped_chain[:jobs]
44
- while job_list.count > 0
45
- job_class_name = job_list[0][:job]
46
- job_class = job_class_name.constantize
47
- break if job_class <= CanvasSync::Jobs::ForkGather
48
- job_list.shift
49
- end
50
-
51
- return nil unless job_list.present?
52
-
53
- if skip_invoke
54
- duped_chain
55
- else
56
- CanvasSync.invoke_next(duped_chain)
57
- true
58
- end
59
- end
60
-
61
- protected
62
-
63
- def self.forked_at_job(job_chain)
64
- fork_item = (job_chain.dig(:fork_state, :forking_path) || []).pop
65
-
66
- if fork_item.present?
67
- CanvasSync::JobLog.find_by(job_id: fork_item)
68
- else
69
- nil
70
- end
71
- end
72
- end
73
- end
74
- end
@@ -1,73 +0,0 @@
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: [], fork_state: { forking_path: ['BLAH'], pre_fork_globals: [{}] }} }
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 forking_path is specified' do
25
- job_chain[:fork_state].delete(:forking_path)
26
- expect(CanvasSync).to receive(:invoke_next)
27
- CanvasSync::Jobs::ForkGather.perform_now(job_chain, {})
28
- end
29
-
30
- it 'pops the most-recent forking_path enrty' do
31
- job_log.update!(fork_count: 1)
32
- expect(CanvasSync).to receive(:invoke_next) do |*args|
33
- expect(args[0][:fork_state][:forking_path]).to eq []
34
- end
35
- CanvasSync::Jobs::ForkGather.perform_now(job_chain, {})
36
- end
37
- end
38
-
39
- describe 'handle_branch_error' do
40
- let(:error) { StandardError.new }
41
-
42
- let(:job_chain) {
43
- {
44
- jobs: [
45
- { job: 'CanvasSync::Jobs::ReportChecker' },
46
- { job: 'CanvasSync::Jobs::ReportChecker' },
47
- { job: 'CanvasSync::Jobs::ForkGather' },
48
- { job: 'CanvasSync::Jobs::ReportChecker' },
49
- ],
50
- fork_state: {
51
- forking_path: ['BLAH'],
52
- }
53
- }
54
- }
55
-
56
- it 'skips to and performs the next ForkGatherJob' do
57
- expect(CanvasSync).to receive(:invoke_next) do |*args|
58
- expect(args[0][:jobs][0][:job]).to eq 'CanvasSync::Jobs::ForkGather'
59
- end
60
- expect(CanvasSync::Jobs::ForkGather.handle_branch_error(error, job_chain: job_chain)).to be true
61
- end
62
-
63
- it 'does nothing if no ForkGather is in the chain' do
64
- job_chain[:jobs].delete_at(2)
65
- expect(CanvasSync::Jobs::ForkGather.handle_branch_error(error, job_chain: job_chain)).to be nil
66
- end
67
-
68
- it 'does nothing if no forking_path is present' do
69
- job_chain[:fork_state][:forking_path] = []
70
- expect(CanvasSync::Jobs::ForkGather.handle_branch_error(error, job_chain: job_chain)).to be nil
71
- end
72
- end
73
- end
Binary file