canvas_sync 0.23.5 → 0.24.0
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/Rakefile +2 -4
- data/lib/canvas_sync/version.rb +1 -1
- data/lib/canvas_sync.rb +6 -4
- data/spec/canvas_sync/canvas_sync_spec.rb +11 -11
- data/spec/canvas_sync/live_events/process_event_job_spec.rb +1 -0
- data/spec/{dummy → internal}/app/models/application_record.rb +1 -0
- data/spec/{dummy → internal}/app/models/content_migration.rb +0 -0
- data/spec/{dummy → internal}/app/models/course.rb +0 -1
- data/spec/{dummy → internal}/app/models/course_nickname.rb +0 -0
- data/spec/{dummy → internal}/app/models/learning_outcome.rb +0 -0
- data/spec/{dummy → internal}/app/services/live_events/assignment_event.rb +0 -0
- data/spec/{dummy → internal}/app/services/live_events/course_event.rb +0 -0
- data/spec/{dummy → internal}/app/services/live_events/course_section_event.rb +0 -0
- data/spec/{dummy → internal}/app/services/live_events/enrollment_event.rb +0 -0
- data/spec/{dummy → internal}/app/services/live_events/grade_event.rb +0 -0
- data/spec/{dummy → internal}/app/services/live_events/module_event.rb +0 -0
- data/spec/{dummy → internal}/app/services/live_events/module_item_event.rb +0 -0
- data/spec/{dummy → internal}/app/services/live_events/submission_event.rb +0 -0
- data/spec/{dummy → internal}/app/services/live_events/syllabus_event.rb +0 -0
- data/spec/{dummy → internal}/app/services/live_events/user_event.rb +0 -0
- data/spec/internal/bin/rails +9 -0
- data/spec/internal/config/database.yml +5 -0
- data/spec/internal/config/routes.rb +5 -0
- data/spec/internal/config/storage.yml +3 -0
- data/spec/{dummy/db/migrate/20220926221926_create_users.rb → internal/db/migrate/20250912205136_create_users.rb} +0 -0
- data/spec/{dummy/db/migrate/20201016181346_create_pseudonyms.rb → internal/db/migrate/20250912205137_create_pseudonyms.rb} +0 -0
- data/spec/{dummy/db/migrate/20200415171620_create_groups.rb → internal/db/migrate/20250912205139_create_groups.rb} +0 -0
- data/spec/{dummy/db/migrate/20200416214248_create_group_memberships.rb → internal/db/migrate/20250912205140_create_group_memberships.rb} +0 -0
- data/spec/{dummy/db/migrate/20190702203622_create_accounts.rb → internal/db/migrate/20250912205141_create_accounts.rb} +0 -0
- data/spec/{dummy/db/migrate/20190702203623_create_terms.rb → internal/db/migrate/20250912205142_create_terms.rb} +0 -0
- data/spec/{dummy/db/migrate/20190702203625_create_sections.rb → internal/db/migrate/20250912205144_create_sections.rb} +0 -0
- data/spec/{dummy/db/migrate/20190702203626_create_assignments.rb → internal/db/migrate/20250912205145_create_assignments.rb} +0 -0
- data/spec/{dummy/db/migrate/20190702203627_create_submissions.rb → internal/db/migrate/20250912205146_create_submissions.rb} +0 -0
- data/spec/{dummy/db/migrate/20190927204545_create_roles.rb → internal/db/migrate/20250912205147_create_roles.rb} +2 -2
- data/spec/{dummy/db/migrate/20190927204546_create_admins.rb → internal/db/migrate/20250912205148_create_admins.rb} +0 -0
- data/spec/{dummy/db/migrate/20190702203630_create_assignment_groups.rb → internal/db/migrate/20250912205149_create_assignment_groups.rb} +0 -0
- data/spec/{dummy/db/migrate/20190702203631_create_context_modules.rb → internal/db/migrate/20250912205150_create_context_modules.rb} +0 -0
- data/spec/{dummy/db/migrate/20190702203632_create_context_module_items.rb → internal/db/migrate/20250912205151_create_context_module_items.rb} +0 -0
- data/spec/{dummy/db/migrate/20210907233329_create_user_observers.rb → internal/db/migrate/20250912205152_create_user_observers.rb} +0 -0
- data/spec/{dummy/db/migrate/20210907233330_create_grading_periods.rb → internal/db/migrate/20250912205153_create_grading_periods.rb} +0 -0
- data/spec/{dummy/db/migrate/20211001184920_create_grading_period_groups.rb → internal/db/migrate/20250912205154_create_grading_period_groups.rb} +0 -0
- data/spec/{dummy/db/migrate/20220308072643_create_content_migrations.rb → internal/db/migrate/20250912205155_create_content_migrations.rb} +0 -0
- data/spec/{dummy/db/migrate/20220712210559_create_learning_outcomes.rb → internal/db/migrate/20250912205156_create_learning_outcomes.rb} +0 -0
- data/spec/{dummy/db/migrate/20240523101010_create_learning_outcome_results.rb → internal/db/migrate/20250912205157_create_learning_outcome_results.rb} +0 -0
- data/spec/{dummy/db/migrate/20240510094100_create_rubric_associations.rb → internal/db/migrate/20250912205160_create_rubric_associations.rb} +0 -0
- data/spec/{dummy/db/migrate/20240510101100_create_rubric_assessments.rb → internal/db/migrate/20250912205161_create_rubric_assessments.rb} +0 -0
- data/spec/{dummy/db/migrate/20240828161300_create_course_progresses.rb → internal/db/migrate/20250912205162_create_course_progresses.rb} +0 -0
- data/spec/internal/db/schema.rb +6 -0
- data/spec/spec_helper.rb +8 -4
- metadata +182 -372
- data/lib/canvas_sync/job_batches/batch.rb +0 -595
- data/lib/canvas_sync/job_batches/callback.rb +0 -135
- data/lib/canvas_sync/job_batches/chain_builder.rb +0 -247
- data/lib/canvas_sync/job_batches/compat/active_job.rb +0 -108
- data/lib/canvas_sync/job_batches/compat/sidekiq/web/batches_assets/css/styles.less +0 -182
- data/lib/canvas_sync/job_batches/compat/sidekiq/web/batches_assets/js/batch_tree.js +0 -108
- data/lib/canvas_sync/job_batches/compat/sidekiq/web/batches_assets/js/util.js +0 -2
- data/lib/canvas_sync/job_batches/compat/sidekiq/web/helpers.rb +0 -41
- data/lib/canvas_sync/job_batches/compat/sidekiq/web/views/_batch_tree.erb +0 -6
- data/lib/canvas_sync/job_batches/compat/sidekiq/web/views/_batches_table.erb +0 -44
- data/lib/canvas_sync/job_batches/compat/sidekiq/web/views/_common.erb +0 -13
- data/lib/canvas_sync/job_batches/compat/sidekiq/web/views/_jobs_table.erb +0 -21
- data/lib/canvas_sync/job_batches/compat/sidekiq/web/views/_pagination.erb +0 -26
- data/lib/canvas_sync/job_batches/compat/sidekiq/web/views/batch.erb +0 -81
- data/lib/canvas_sync/job_batches/compat/sidekiq/web/views/batches.erb +0 -23
- data/lib/canvas_sync/job_batches/compat/sidekiq/web/views/pool.erb +0 -137
- data/lib/canvas_sync/job_batches/compat/sidekiq/web/views/pools.erb +0 -47
- data/lib/canvas_sync/job_batches/compat/sidekiq/web.rb +0 -218
- data/lib/canvas_sync/job_batches/compat/sidekiq.rb +0 -149
- data/lib/canvas_sync/job_batches/compat.rb +0 -20
- data/lib/canvas_sync/job_batches/context_hash.rb +0 -157
- data/lib/canvas_sync/job_batches/hier_batch_ids.lua +0 -25
- data/lib/canvas_sync/job_batches/jobs/base_job.rb +0 -5
- data/lib/canvas_sync/job_batches/jobs/concurrent_batch_job.rb +0 -20
- data/lib/canvas_sync/job_batches/jobs/managed_batch_job.rb +0 -175
- data/lib/canvas_sync/job_batches/jobs/serial_batch_job.rb +0 -20
- data/lib/canvas_sync/job_batches/pool.rb +0 -254
- data/lib/canvas_sync/job_batches/pool_refill.lua +0 -47
- data/lib/canvas_sync/job_batches/redis_model.rb +0 -67
- data/lib/canvas_sync/job_batches/redis_script.rb +0 -161
- data/lib/canvas_sync/job_batches/schedule_callback.lua +0 -14
- data/lib/canvas_sync/job_batches/status.rb +0 -89
- data/lib/canvas_sync/job_uniqueness/compat/active_job.rb +0 -75
- data/lib/canvas_sync/job_uniqueness/compat/sidekiq.rb +0 -135
- data/lib/canvas_sync/job_uniqueness/compat.rb +0 -20
- data/lib/canvas_sync/job_uniqueness/configuration.rb +0 -25
- data/lib/canvas_sync/job_uniqueness/job_uniqueness.rb +0 -47
- data/lib/canvas_sync/job_uniqueness/lock_context.rb +0 -199
- data/lib/canvas_sync/job_uniqueness/locksmith.rb +0 -92
- data/lib/canvas_sync/job_uniqueness/on_conflict/base.rb +0 -32
- data/lib/canvas_sync/job_uniqueness/on_conflict/log.rb +0 -13
- data/lib/canvas_sync/job_uniqueness/on_conflict/null_strategy.rb +0 -9
- data/lib/canvas_sync/job_uniqueness/on_conflict/raise.rb +0 -11
- data/lib/canvas_sync/job_uniqueness/on_conflict/reject.rb +0 -21
- data/lib/canvas_sync/job_uniqueness/on_conflict/reschedule.rb +0 -20
- data/lib/canvas_sync/job_uniqueness/on_conflict.rb +0 -62
- data/lib/canvas_sync/job_uniqueness/strategy/base.rb +0 -107
- data/lib/canvas_sync/job_uniqueness/strategy/until_and_while_executing.rb +0 -35
- data/lib/canvas_sync/job_uniqueness/strategy/until_executed.rb +0 -20
- data/lib/canvas_sync/job_uniqueness/strategy/until_executing.rb +0 -20
- data/lib/canvas_sync/job_uniqueness/strategy/until_expired.rb +0 -16
- data/lib/canvas_sync/job_uniqueness/strategy/while_executing.rb +0 -26
- data/lib/canvas_sync/job_uniqueness/strategy.rb +0 -27
- data/lib/canvas_sync/job_uniqueness/unique_job_common.rb +0 -79
- data/spec/dummy/README.rdoc +0 -1
- data/spec/dummy/Rakefile +0 -6
- data/spec/dummy/app/services/live_events/assignment_created_event.rb +0 -12
- data/spec/dummy/app/services/live_events/assignment_updated_event.rb +0 -12
- data/spec/dummy/app/services/live_events/base_event.rb +0 -52
- data/spec/dummy/app/services/live_events/course_created_event.rb +0 -12
- data/spec/dummy/app/services/live_events/course_section_created_event.rb +0 -12
- data/spec/dummy/app/services/live_events/course_section_updated_event.rb +0 -12
- data/spec/dummy/app/services/live_events/course_updated_event.rb +0 -12
- data/spec/dummy/app/services/live_events/enrollment_created_event.rb +0 -12
- data/spec/dummy/app/services/live_events/enrollment_updated_event.rb +0 -12
- data/spec/dummy/app/services/live_events/grade_changed_event.rb +0 -12
- data/spec/dummy/app/services/live_events/module_created_event.rb +0 -12
- data/spec/dummy/app/services/live_events/module_item_created_event.rb +0 -12
- data/spec/dummy/app/services/live_events/module_item_updated_event.rb +0 -12
- data/spec/dummy/app/services/live_events/module_updated_event.rb +0 -12
- data/spec/dummy/app/services/live_events/submission_created_event.rb +0 -12
- data/spec/dummy/app/services/live_events/submission_updated_event.rb +0 -12
- data/spec/dummy/app/services/live_events/syllabus_updated_event.rb +0 -12
- data/spec/dummy/app/services/live_events/user_created_event.rb +0 -12
- data/spec/dummy/app/services/live_events/user_updated_event.rb +0 -12
- data/spec/dummy/bin/rails +0 -4
- data/spec/dummy/config/application.rb +0 -39
- data/spec/dummy/config/boot.rb +0 -5
- data/spec/dummy/config/database.yml +0 -25
- data/spec/dummy/config/environment.rb +0 -5
- data/spec/dummy/config/environments/development.rb +0 -41
- data/spec/dummy/config/environments/test.rb +0 -44
- data/spec/dummy/config/initializers/assets.rb +0 -11
- data/spec/dummy/config/initializers/session_store.rb +0 -3
- data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
- data/spec/dummy/config/routes.rb +0 -3
- data/spec/dummy/config/secrets.yml +0 -22
- data/spec/dummy/config.ru +0 -4
- data/spec/dummy/db/schema.rb +0 -563
- data/spec/job_batching/batch_spec.rb +0 -531
- data/spec/job_batching/callback_spec.rb +0 -38
- data/spec/job_batching/compat/active_job_spec.rb +0 -107
- data/spec/job_batching/compat/sidekiq_spec.rb +0 -127
- data/spec/job_batching/context_hash_spec.rb +0 -54
- data/spec/job_batching/flow_spec.rb +0 -82
- data/spec/job_batching/integration/fail_then_succeed.rb +0 -42
- data/spec/job_batching/integration/integration.rb +0 -57
- data/spec/job_batching/integration/nested.rb +0 -88
- data/spec/job_batching/integration/simple.rb +0 -47
- data/spec/job_batching/integration/workflow.rb +0 -134
- data/spec/job_batching/integration_helper.rb +0 -50
- data/spec/job_batching/pool_spec.rb +0 -161
- data/spec/job_batching/status_spec.rb +0 -76
- data/spec/job_batching/support/base_job.rb +0 -14
- data/spec/job_batching/support/sample_callback.rb +0 -2
- data/spec/job_uniqueness/compat/active_job_spec.rb +0 -49
- data/spec/job_uniqueness/compat/sidekiq_spec.rb +0 -68
- data/spec/job_uniqueness/lock_context_spec.rb +0 -106
- data/spec/job_uniqueness/on_conflict/log_spec.rb +0 -11
- data/spec/job_uniqueness/on_conflict/raise_spec.rb +0 -10
- data/spec/job_uniqueness/on_conflict/reschedule_spec.rb +0 -63
- data/spec/job_uniqueness/on_conflict_spec.rb +0 -16
- data/spec/job_uniqueness/spec_helper.rb +0 -17
- data/spec/job_uniqueness/strategy/base_spec.rb +0 -100
- data/spec/job_uniqueness/strategy/until_and_while_executing_spec.rb +0 -48
- data/spec/job_uniqueness/strategy/until_executed_spec.rb +0 -23
- data/spec/job_uniqueness/strategy/until_executing_spec.rb +0 -23
- data/spec/job_uniqueness/strategy/until_expired_spec.rb +0 -23
- data/spec/job_uniqueness/strategy/while_executing_spec.rb +0 -33
- data/spec/job_uniqueness/support/lock_strategy.rb +0 -28
- data/spec/job_uniqueness/support/on_conflict.rb +0 -24
- data/spec/job_uniqueness/support/test_worker.rb +0 -19
- data/spec/job_uniqueness/unique_job_common_spec.rb +0 -45
- /data/spec/{dummy → internal}/app/models/account.rb +0 -0
- /data/spec/{dummy → internal}/app/models/admin.rb +0 -0
- /data/spec/{dummy → internal}/app/models/assignment.rb +0 -0
- /data/spec/{dummy → internal}/app/models/assignment_group.rb +0 -0
- /data/spec/{dummy → internal}/app/models/assignment_override.rb +0 -0
- /data/spec/{dummy → internal}/app/models/context_module.rb +0 -0
- /data/spec/{dummy → internal}/app/models/context_module_item.rb +0 -0
- /data/spec/{dummy → internal}/app/models/course_progress.rb +0 -0
- /data/spec/{dummy → internal}/app/models/enrollment.rb +0 -0
- /data/spec/{dummy → internal}/app/models/grading_period.rb +0 -0
- /data/spec/{dummy → internal}/app/models/grading_period_group.rb +0 -0
- /data/spec/{dummy → internal}/app/models/group.rb +0 -0
- /data/spec/{dummy → internal}/app/models/group_membership.rb +0 -0
- /data/spec/{dummy → internal}/app/models/learning_outcome_result.rb +0 -0
- /data/spec/{dummy → internal}/app/models/pseudonym.rb +0 -0
- /data/spec/{dummy → internal}/app/models/role.rb +0 -0
- /data/spec/{dummy → internal}/app/models/rubric.rb +0 -0
- /data/spec/{dummy → internal}/app/models/rubric_assessment.rb +0 -0
- /data/spec/{dummy → internal}/app/models/rubric_association.rb +0 -0
- /data/spec/{dummy → internal}/app/models/score.rb +0 -0
- /data/spec/{dummy → internal}/app/models/section.rb +0 -0
- /data/spec/{dummy → internal}/app/models/submission.rb +0 -0
- /data/spec/{dummy → internal}/app/models/term.rb +0 -0
- /data/spec/{dummy → internal}/app/models/user.rb +0 -0
- /data/spec/{dummy → internal}/app/models/user_observer.rb +0 -0
- /data/spec/{dummy/db/migrate/20190702203621_create_courses.rb → internal/db/migrate/20250912205138_create_courses.rb} +0 -0
- /data/spec/{dummy/db/migrate/20190702203624_create_enrollments.rb → internal/db/migrate/20250912205143_create_enrollments.rb} +0 -0
- /data/spec/{dummy/db/migrate/20250319194134_create_course_nicknames.rb → internal/db/migrate/20250912205158_create_course_nicknames.rb} +0 -0
- /data/spec/{dummy/db/migrate/20250319194135_create_rubrics.rb → internal/db/migrate/20250912205159_create_rubrics.rb} +0 -0
- /data/spec/{dummy/db/migrate/20241223080202_create_assignment_overrides.rb → internal/db/migrate/20250912205163_create_assignment_overrides.rb} +0 -0
- /data/spec/{dummy/db/migrate/20250626194330_create_scores.rb → internal/db/migrate/20250912205164_create_scores.rb} +0 -0
@@ -1,161 +0,0 @@
|
|
1
|
-
require 'pathname'
|
2
|
-
require 'digest/sha1'
|
3
|
-
require 'erb'
|
4
|
-
|
5
|
-
# Modified from https://github.com/Shopify/wolverine/blob/master/lib/wolverine/script.rb
|
6
|
-
|
7
|
-
module CanvasSync::JobBatches
|
8
|
-
# {RedisScript} represents a lua script in the filesystem. It loads the script
|
9
|
-
# from disk and handles talking to redis to execute it. Error handling
|
10
|
-
# is handled by {LuaError}.
|
11
|
-
class RedisScript
|
12
|
-
|
13
|
-
# Loads the script file from disk and calculates its +SHA1+ sum.
|
14
|
-
#
|
15
|
-
# @param file [Pathname] the full path to the indicated file
|
16
|
-
def initialize(file)
|
17
|
-
@file = Pathname.new(file)
|
18
|
-
end
|
19
|
-
|
20
|
-
# Passes the script and supplied arguments to redis for evaulation.
|
21
|
-
# It first attempts to use a script redis has already cached by using
|
22
|
-
# the +EVALSHA+ command, but falls back to providing the full script
|
23
|
-
# text via +EVAL+ if redis has not seen this script before. Future
|
24
|
-
# invocations will then use +EVALSHA+ without erroring.
|
25
|
-
#
|
26
|
-
# @param redis [Redis] the redis connection to run against
|
27
|
-
# @param args [*Objects] the arguments to the script
|
28
|
-
# @return [Object] the value passed back by redis after script execution
|
29
|
-
# @raise [LuaError] if the script failed to compile of encountered a
|
30
|
-
# runtime error
|
31
|
-
def call(redis, *args)
|
32
|
-
t = Time.now
|
33
|
-
begin
|
34
|
-
redis.evalsha(digest, *args)
|
35
|
-
rescue => e
|
36
|
-
e.message =~ /NOSCRIPT/ ? redis.eval(content, *args) : raise
|
37
|
-
end
|
38
|
-
rescue => e
|
39
|
-
if LuaError.intercepts?(e)
|
40
|
-
raise LuaError.new(e, @file, content)
|
41
|
-
else
|
42
|
-
raise
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def content
|
47
|
-
@content ||= load_lua(@file)
|
48
|
-
end
|
49
|
-
|
50
|
-
def digest
|
51
|
-
@digest ||= Digest::SHA1.hexdigest content
|
52
|
-
end
|
53
|
-
|
54
|
-
private
|
55
|
-
|
56
|
-
def script_path
|
57
|
-
Rails.root + 'app/redis_lua'
|
58
|
-
end
|
59
|
-
|
60
|
-
def relative_path
|
61
|
-
@path ||= @file.relative_path_from(script_path)
|
62
|
-
end
|
63
|
-
|
64
|
-
def load_lua(file)
|
65
|
-
TemplateContext.new(script_path).template(script_path + file)
|
66
|
-
end
|
67
|
-
|
68
|
-
class TemplateContext
|
69
|
-
def initialize(script_path)
|
70
|
-
@script_path = script_path
|
71
|
-
end
|
72
|
-
|
73
|
-
def template(pathname)
|
74
|
-
@partial_templates ||= {}
|
75
|
-
ERB.new(File.read(pathname)).result binding
|
76
|
-
end
|
77
|
-
|
78
|
-
# helper method to include a lua partial within another lua script
|
79
|
-
#
|
80
|
-
# @param relative_path [String] the relative path to the script from
|
81
|
-
# `script_path`
|
82
|
-
def include_partial(relative_path)
|
83
|
-
unless @partial_templates.has_key? relative_path
|
84
|
-
@partial_templates[relative_path] = nil
|
85
|
-
template( Pathname.new("#{@script_path}/#{relative_path}") )
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
# Reformats errors raised by redis representing failures while executing
|
91
|
-
# a lua script. The default errors have confusing messages and backtraces,
|
92
|
-
# and a type of +RuntimeError+. This class improves the message and
|
93
|
-
# modifies the backtrace to include the lua script itself in a reasonable
|
94
|
-
# way.
|
95
|
-
class LuaError < StandardError
|
96
|
-
PATTERN = /ERR Error (compiling|running) script \(.*?\): .*?:(\d+): (.*)/
|
97
|
-
WOLVERINE_LIB_PATH = File.expand_path('../../', __FILE__)
|
98
|
-
CONTEXT_LINE_NUMBER = 2
|
99
|
-
|
100
|
-
attr_reader :error, :file, :content
|
101
|
-
|
102
|
-
# Is this error one that should be reformatted?
|
103
|
-
#
|
104
|
-
# @param error [StandardError] the original error raised by redis
|
105
|
-
# @return [Boolean] is this an error that should be reformatted?
|
106
|
-
def self.intercepts? error
|
107
|
-
error.message =~ PATTERN
|
108
|
-
end
|
109
|
-
|
110
|
-
# Initialize a new {LuaError} from an existing redis error, adjusting
|
111
|
-
# the message and backtrace in the process.
|
112
|
-
#
|
113
|
-
# @param error [StandardError] the original error raised by redis
|
114
|
-
# @param file [Pathname] full path to the lua file the error ocurred in
|
115
|
-
# @param content [String] lua file content the error ocurred in
|
116
|
-
def initialize error, file, content
|
117
|
-
@error = error
|
118
|
-
@file = file
|
119
|
-
@content = content
|
120
|
-
|
121
|
-
@error.message =~ PATTERN
|
122
|
-
_stage, line_number, message = $1, $2, $3
|
123
|
-
error_context = generate_error_context(content, line_number.to_i)
|
124
|
-
|
125
|
-
super "#{message}\n\n#{error_context}\n\n"
|
126
|
-
set_backtrace generate_backtrace file, line_number
|
127
|
-
end
|
128
|
-
|
129
|
-
private
|
130
|
-
|
131
|
-
def generate_error_context(content, line_number)
|
132
|
-
lines = content.lines.to_a
|
133
|
-
beginning_line_number = [1, line_number - CONTEXT_LINE_NUMBER].max
|
134
|
-
ending_line_number = [lines.count, line_number + CONTEXT_LINE_NUMBER].min
|
135
|
-
line_number_width = ending_line_number.to_s.length
|
136
|
-
|
137
|
-
(beginning_line_number..ending_line_number).map do |number|
|
138
|
-
indicator = number == line_number ? '=>' : ' '
|
139
|
-
formatted_number = "%#{line_number_width}d" % number
|
140
|
-
" #{indicator} #{formatted_number}: #{lines[number - 1]}"
|
141
|
-
end.join.chomp
|
142
|
-
end
|
143
|
-
|
144
|
-
def generate_backtrace(file, line_number)
|
145
|
-
pre_wolverine = backtrace_before_entering_wolverine(@error.backtrace)
|
146
|
-
index_of_first_wolverine_line = (@error.backtrace.size - pre_wolverine.size - 1)
|
147
|
-
pre_wolverine.unshift(@error.backtrace[index_of_first_wolverine_line])
|
148
|
-
pre_wolverine.unshift("#{file}:#{line_number}")
|
149
|
-
pre_wolverine
|
150
|
-
end
|
151
|
-
|
152
|
-
def backtrace_before_entering_wolverine(backtrace)
|
153
|
-
backtrace.reverse.take_while { |line| ! line_from_wolverine(line) }.reverse
|
154
|
-
end
|
155
|
-
|
156
|
-
def line_from_wolverine(line)
|
157
|
-
line.split(':').first.include?(WOLVERINE_LIB_PATH)
|
158
|
-
end
|
159
|
-
end
|
160
|
-
end
|
161
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
|
2
|
-
local previously_scheduled = redis.call('HGET', KEYS[1], ARGV[1])
|
3
|
-
redis.call('HSET', KEYS[1], ARGV[1], 'true')
|
4
|
-
|
5
|
-
if previously_scheduled ~= 'true' then
|
6
|
-
local pcb_key = KEYS[1] .. '-pending_callbacks'
|
7
|
-
redis.call('SADD', pcb_key, ARGV[1] .. '-finalize')
|
8
|
-
if ARGV[2] == 'true' then
|
9
|
-
redis.call('SADD', pcb_key, ARGV[1])
|
10
|
-
end
|
11
|
-
redis.call('EXPIRE', pcb_key, ARGV[3])
|
12
|
-
end
|
13
|
-
|
14
|
-
return previously_scheduled
|
@@ -1,89 +0,0 @@
|
|
1
|
-
module CanvasSync::JobBatches
|
2
|
-
class Batch
|
3
|
-
class Status
|
4
|
-
attr_reader :bid
|
5
|
-
|
6
|
-
def initialize(bid)
|
7
|
-
bid = bid.bid if bid.is_a?(Batch)
|
8
|
-
@bid = bid
|
9
|
-
end
|
10
|
-
|
11
|
-
def join
|
12
|
-
raise "Not supported"
|
13
|
-
end
|
14
|
-
|
15
|
-
def pending
|
16
|
-
Batch.redis { |r| r.hget("BID-#{bid}", 'pending') }.to_i
|
17
|
-
end
|
18
|
-
|
19
|
-
def failures
|
20
|
-
Batch.redis { |r| r.scard("BID-#{bid}-failed") }.to_i
|
21
|
-
end
|
22
|
-
|
23
|
-
def dead
|
24
|
-
Batch.redis { |r| r.scard("BID-#{bid}-dead") }.to_i
|
25
|
-
end
|
26
|
-
|
27
|
-
def completed_count
|
28
|
-
job_count - pending
|
29
|
-
end
|
30
|
-
|
31
|
-
def job_count
|
32
|
-
Batch.redis { |r| r.hget("BID-#{bid}", "job_count") }.to_i
|
33
|
-
end
|
34
|
-
|
35
|
-
def created_at
|
36
|
-
Batch.redis { |r| r.hget("BID-#{bid}", 'created_at') }
|
37
|
-
end
|
38
|
-
|
39
|
-
def parent_bid
|
40
|
-
Batch.redis { |r| r.hget("BID-#{bid}", "parent_bid") }
|
41
|
-
end
|
42
|
-
|
43
|
-
def failure_info
|
44
|
-
Batch.redis { |r| r.smembers("BID-#{bid}-failed") } || []
|
45
|
-
end
|
46
|
-
|
47
|
-
def complete?
|
48
|
-
'true' == Batch.redis { |r| r.hget("BID-#{bid}", 'complete') }
|
49
|
-
end
|
50
|
-
|
51
|
-
def success?
|
52
|
-
'true' == Batch.redis { |r| r.hget("BID-#{bid}", 'success') }
|
53
|
-
end
|
54
|
-
|
55
|
-
def child_count
|
56
|
-
Batch.redis { |r| r.hget("BID-#{bid}", 'children') }.to_i
|
57
|
-
end
|
58
|
-
|
59
|
-
def completed_children_count
|
60
|
-
Batch.redis { |r| r.scard("BID-#{bid}-batches-complete") }.to_i
|
61
|
-
end
|
62
|
-
|
63
|
-
def successful_children_count
|
64
|
-
Batch.redis { |r| r.scard("BID-#{bid}-batches-success") }.to_i
|
65
|
-
end
|
66
|
-
|
67
|
-
def failed_children_count
|
68
|
-
Batch.redis { |r| r.scard("BID-#{bid}-batches-failed") }.to_i
|
69
|
-
end
|
70
|
-
|
71
|
-
def data
|
72
|
-
{
|
73
|
-
bid: bid,
|
74
|
-
failures: failures,
|
75
|
-
pending: pending,
|
76
|
-
created_at: created_at,
|
77
|
-
complete: complete?,
|
78
|
-
success: success?,
|
79
|
-
failure_info: failure_info,
|
80
|
-
parent_bid: parent_bid,
|
81
|
-
child_count: child_count,
|
82
|
-
completed_children_count: completed_children_count,
|
83
|
-
successful_children_count: successful_children_count,
|
84
|
-
failed_children_count: failed_children_count,
|
85
|
-
}
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
@@ -1,75 +0,0 @@
|
|
1
|
-
|
2
|
-
module CanvasSync::JobUniqueness
|
3
|
-
module Compat
|
4
|
-
module ActiveJob
|
5
|
-
|
6
|
-
class ActiveJobLockContext < LockContext
|
7
|
-
def job_scheduled_at
|
8
|
-
job_instance&.scheduled_at
|
9
|
-
end
|
10
|
-
|
11
|
-
def reenqueue(schedule_in:)
|
12
|
-
job_class.set(
|
13
|
-
queue: job_queue.to_sym,
|
14
|
-
wait: schedule_in,
|
15
|
-
priortity: job_instance.priority,
|
16
|
-
).perform_later(*job_instance.arguments)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
module UniqueJobExtension
|
21
|
-
extend ActiveSupport::Concern
|
22
|
-
|
23
|
-
included do
|
24
|
-
set_callback(:enqueue, :around, prepend: true) do |job, block|
|
25
|
-
ctx = uniqueness_lock_context
|
26
|
-
@uniqueness_cache_data = ctx.cache_data
|
27
|
-
ctx.handle_lifecycle!(:enqueue, &block)
|
28
|
-
end
|
29
|
-
|
30
|
-
around_perform do |job, block|
|
31
|
-
ctx = uniqueness_lock_context
|
32
|
-
ctx.handle_lifecycle!(:perform, &block)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def serialize
|
37
|
-
super.tap do |data|
|
38
|
-
data['uniqueness_cache_data'] = @uniqueness_cache_data.stringify_keys
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def deserialize(data)
|
43
|
-
super
|
44
|
-
@uniqueness_cache_data = data['uniqueness_cache_data']&.symbolize_keys
|
45
|
-
end
|
46
|
-
|
47
|
-
def uniqueness_lock_context
|
48
|
-
ActiveJobLockContext.new({
|
49
|
-
job_clazz: self.class,
|
50
|
-
jid: self.job_id,
|
51
|
-
args: self.arguments,
|
52
|
-
queue: self.queue_name,
|
53
|
-
**(@uniqueness_cache_data || {})
|
54
|
-
}, job_instance: self)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
module JobExtension
|
59
|
-
extend ActiveSupport::Concern
|
60
|
-
include UniqueJobCommon
|
61
|
-
|
62
|
-
class_methods do
|
63
|
-
def ensure_uniqueness(**kwargs)
|
64
|
-
super(**kwargs)
|
65
|
-
include UniqueJobExtension
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def self.configure
|
71
|
-
::ActiveJob::Base.include JobExtension
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
@@ -1,135 +0,0 @@
|
|
1
|
-
|
2
|
-
module CanvasSync::JobUniqueness
|
3
|
-
module Compat
|
4
|
-
module Sidekiq
|
5
|
-
module WorkerExtension
|
6
|
-
extend ActiveSupport::Concern
|
7
|
-
include UniqueJobCommon
|
8
|
-
|
9
|
-
class_methods do
|
10
|
-
def ensure_uniqueness(**kwargs)
|
11
|
-
super(**kwargs)
|
12
|
-
if !(defined?(@@validated_config) && @@validated_config)
|
13
|
-
Compat::Sidekiq.validate_middleware_placement!()
|
14
|
-
@@validated_config = true
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
class SidekiqLockContext < LockContext
|
21
|
-
def job_scheduled_at
|
22
|
-
@job_instance&.[]("at")
|
23
|
-
end
|
24
|
-
|
25
|
-
def reenqueue(schedule_in:)
|
26
|
-
job_class.set(queue: job_queue.to_sym).perform_in(schedule_in, *@job_instance["args"])
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
class CommonMiddleware
|
31
|
-
def lock_context(msg)
|
32
|
-
opts = worker_uniqueness(msg)
|
33
|
-
return nil unless opts
|
34
|
-
|
35
|
-
SidekiqLockContext.new({
|
36
|
-
job_clazz: msg['class'],
|
37
|
-
jid: msg['jid'],
|
38
|
-
queue: msg['queue'],
|
39
|
-
args: msg['args'],
|
40
|
-
# kwargs: msg['kwargs'],
|
41
|
-
**(msg['uniqueness_cache_data']&.symbolize_keys || {}),
|
42
|
-
}, job_instance: msg)
|
43
|
-
end
|
44
|
-
|
45
|
-
def worker_uniqueness(msg)
|
46
|
-
return nil if Compat::Sidekiq.is_activejob_job?(msg)
|
47
|
-
|
48
|
-
worker_class = msg['class'].constantize
|
49
|
-
return nil unless worker_class.respond_to?(:unique_job_options)
|
50
|
-
|
51
|
-
worker_class.unique_job_options
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
class ClientMiddleware < CommonMiddleware
|
56
|
-
include ::Sidekiq::ClientMiddleware if defined? ::Sidekiq::ClientMiddleware
|
57
|
-
|
58
|
-
def call(_worker, msg, _queue, _redis_pool = nil, &blk)
|
59
|
-
ctx = lock_context(msg)
|
60
|
-
return blk.call unless ctx
|
61
|
-
msg['uniqueness_cache_data'] = ctx.cache_data.stringify_keys
|
62
|
-
ctx.handle_lifecycle!(:enqueue, &blk)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
class ServerMiddleware < CommonMiddleware
|
67
|
-
include ::Sidekiq::ServerMiddleware if defined? ::Sidekiq::ServerMiddleware
|
68
|
-
|
69
|
-
def call(_worker, msg, _queue, &blk)
|
70
|
-
ctx = lock_context(msg)
|
71
|
-
return blk.call unless ctx
|
72
|
-
ctx.handle_lifecycle!(:perform, &blk)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def self.is_activejob_job?(msg)
|
77
|
-
return false unless defined?(::ActiveJob)
|
78
|
-
|
79
|
-
msg['class'] == 'ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper' && (msg['wrapped'].to_s).constantize < Compat::ActiveJob::UniqueJobExtension
|
80
|
-
end
|
81
|
-
|
82
|
-
def self.validate_middleware_order(chain, order)
|
83
|
-
chain_classes = chain.entries.map(&:klass)
|
84
|
-
filtered = chain_classes.select { |klass| order.include?(klass) }
|
85
|
-
raise "Middleware chain does not contain all required middleware: #{order - filtered}" unless order.all? { |klass| filtered.include?(klass) }
|
86
|
-
raise "Middleware must be in order: #{order.inspect}" if filtered != order
|
87
|
-
end
|
88
|
-
|
89
|
-
def self.sidekiq_middleware(placement, &blk)
|
90
|
-
install_middleware = ->(config) do
|
91
|
-
config.send("#{placement}_middleware") do |chain|
|
92
|
-
blk.call(chain)
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
::Sidekiq.configure_client(&install_middleware) if placement == :client
|
97
|
-
::Sidekiq.configure_server(&install_middleware)
|
98
|
-
end
|
99
|
-
|
100
|
-
def self.validate_middleware_placement!
|
101
|
-
sidekiq_middleware(:client) do |chain|
|
102
|
-
# Unique middleware must come _before_ the Batch middleware so that the uniqueness middleware can wrap the job in a batch
|
103
|
-
validate_middleware_order(chain, [
|
104
|
-
CanvasSync::JobUniqueness::Compat::Sidekiq::ClientMiddleware,
|
105
|
-
CanvasSync::JobBatches::Compat::Sidekiq::ClientMiddleware,
|
106
|
-
])
|
107
|
-
end
|
108
|
-
|
109
|
-
sidekiq_middleware(:server) do |chain|
|
110
|
-
# Unique middleware must com _after_ the Batch middleware so that the Batch is loaded before reaching the uniqueness middleware
|
111
|
-
validate_middleware_order(chain, [
|
112
|
-
CanvasSync::JobBatches::Compat::Sidekiq::ServerMiddleware,
|
113
|
-
CanvasSync::JobUniqueness::Compat::Sidekiq::ServerMiddleware,
|
114
|
-
])
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
def self.configure
|
119
|
-
sidekiq_middleware(:client) do |chain|
|
120
|
-
chain.insert_before CanvasSync::JobBatches::Compat::Sidekiq::ClientMiddleware, Compat::Sidekiq::ClientMiddleware
|
121
|
-
end
|
122
|
-
|
123
|
-
sidekiq_middleware(:server) do |chain|
|
124
|
-
chain.insert_after CanvasSync::JobBatches::Compat::Sidekiq::ServerMiddleware, Compat::Sidekiq::ServerMiddleware
|
125
|
-
end
|
126
|
-
|
127
|
-
::Sidekiq::Worker.extend(ActiveSupport::Concern) unless ::Sidekiq::Worker < ActiveSupport::Concern
|
128
|
-
|
129
|
-
::Sidekiq::Worker.send(:include, Compat::Sidekiq::WorkerExtension)
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
# require_relative 'sidekiq/web'
|
@@ -1,20 +0,0 @@
|
|
1
|
-
|
2
|
-
module CanvasSync::JobUniqueness
|
3
|
-
module Compat
|
4
|
-
def self.load_compat(name)
|
5
|
-
name = name.to_s
|
6
|
-
begin
|
7
|
-
require name
|
8
|
-
rescue LoadError
|
9
|
-
end
|
10
|
-
|
11
|
-
if name.classify.safe_constantize
|
12
|
-
require_relative "./compat/#{name}"
|
13
|
-
"#{self.name}::#{name.classify}".constantize.configure
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
load_compat(:active_job)
|
18
|
-
load_compat(:sidekiq)
|
19
|
-
end
|
20
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
module CanvasSync::JobUniqueness
|
2
|
-
class Configuration
|
3
|
-
include ActiveSupport::Configurable
|
4
|
-
|
5
|
-
config_accessor(:lock_ttl) { 14.days.to_i }
|
6
|
-
config_accessor(:lock_prefix) { 'uniquejob' }
|
7
|
-
config_accessor(:on_conflict) { :raise }
|
8
|
-
|
9
|
-
config_accessor(:lock_strategies) { {} }
|
10
|
-
config_accessor(:conflict_strategies) { {} }
|
11
|
-
|
12
|
-
config_accessor(:redis_version) { nil }
|
13
|
-
def on_conflict=(action)
|
14
|
-
validate_on_conflict_action!(action)
|
15
|
-
|
16
|
-
config.on_conflict = action
|
17
|
-
end
|
18
|
-
|
19
|
-
def validate_on_conflict_action!(action)
|
20
|
-
return if action.nil? || %i[log raise].include?(action) || action.respond_to?(:call)
|
21
|
-
|
22
|
-
raise ActiveJob::Uniqueness::InvalidOnConflictAction, "Unexpected '#{action}' action on conflict"
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,47 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'canvas_sync/job_uniqueness/lock_context'
|
3
|
-
require 'canvas_sync/job_uniqueness/unique_job_common'
|
4
|
-
|
5
|
-
require 'canvas_sync/job_uniqueness/strategy'
|
6
|
-
require 'canvas_sync/job_uniqueness/on_conflict'
|
7
|
-
require 'canvas_sync/job_uniqueness/compat'
|
8
|
-
|
9
|
-
module CanvasSync::JobUniqueness
|
10
|
-
extend ActiveSupport::Autoload
|
11
|
-
|
12
|
-
autoload :Locksmith
|
13
|
-
autoload :Configuration
|
14
|
-
|
15
|
-
class Conflict < StandardError
|
16
|
-
attr_reader :lock_context
|
17
|
-
|
18
|
-
def initialize(lock_context)
|
19
|
-
super()
|
20
|
-
@lock_context = lock_context
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
class CouldNotLockError < StandardError
|
25
|
-
attr_reader :lock_context, :source
|
26
|
-
|
27
|
-
def initialize(lock_context, source:)
|
28
|
-
super()
|
29
|
-
@lock_context = lock_context
|
30
|
-
@source = source
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
class << self
|
35
|
-
def configure
|
36
|
-
yield config
|
37
|
-
end
|
38
|
-
|
39
|
-
def config
|
40
|
-
@config ||= Configuration.new
|
41
|
-
end
|
42
|
-
|
43
|
-
def logger
|
44
|
-
CanvasSync.logger
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|