canvas-jobs 0.9.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.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/db/migrate/20101216224513_create_delayed_jobs.rb +40 -0
  3. data/db/migrate/20110208031356_add_delayed_jobs_tag.rb +14 -0
  4. data/db/migrate/20110426161613_add_delayed_jobs_max_attempts.rb +13 -0
  5. data/db/migrate/20110516225834_add_delayed_jobs_strand.rb +14 -0
  6. data/db/migrate/20110531144916_cleanup_delayed_jobs_indexes.rb +26 -0
  7. data/db/migrate/20110610213249_optimize_delayed_jobs.rb +40 -0
  8. data/db/migrate/20110831210257_add_delayed_jobs_next_in_strand.rb +52 -0
  9. data/db/migrate/20120510004759_delayed_jobs_delete_trigger_lock_for_update.rb +31 -0
  10. data/db/migrate/20120531150712_drop_psql_jobs_pop_fn.rb +15 -0
  11. data/db/migrate/20120607164022_delayed_jobs_use_advisory_locks.rb +80 -0
  12. data/db/migrate/20120607181141_index_jobs_on_locked_by.rb +15 -0
  13. data/db/migrate/20120608191051_add_jobs_run_at_index.rb +15 -0
  14. data/db/migrate/20120927184213_change_delayed_jobs_handler_to_text.rb +13 -0
  15. data/db/migrate/20140505215131_add_failed_jobs_original_job_id.rb +13 -0
  16. data/db/migrate/20140505215510_copy_failed_jobs_original_id.rb +13 -0
  17. data/db/migrate/20140505223637_drop_failed_jobs_original_id.rb +13 -0
  18. data/db/migrate/20140512213941_add_source_to_jobs.rb +15 -0
  19. data/lib/canvas-jobs.rb +1 -0
  20. data/lib/delayed/backend/active_record.rb +297 -0
  21. data/lib/delayed/backend/base.rb +317 -0
  22. data/lib/delayed/backend/redis/bulk_update.lua +40 -0
  23. data/lib/delayed/backend/redis/destroy_job.lua +2 -0
  24. data/lib/delayed/backend/redis/enqueue.lua +29 -0
  25. data/lib/delayed/backend/redis/fail_job.lua +5 -0
  26. data/lib/delayed/backend/redis/find_available.lua +3 -0
  27. data/lib/delayed/backend/redis/functions.rb +57 -0
  28. data/lib/delayed/backend/redis/get_and_lock_next_available.lua +17 -0
  29. data/lib/delayed/backend/redis/includes/jobs_common.lua +203 -0
  30. data/lib/delayed/backend/redis/job.rb +481 -0
  31. data/lib/delayed/backend/redis/set_running.lua +5 -0
  32. data/lib/delayed/backend/redis/tickle_strand.lua +2 -0
  33. data/lib/delayed/batch.rb +56 -0
  34. data/lib/delayed/engine.rb +4 -0
  35. data/lib/delayed/job_tracking.rb +31 -0
  36. data/lib/delayed/lifecycle.rb +83 -0
  37. data/lib/delayed/message_sending.rb +130 -0
  38. data/lib/delayed/performable_method.rb +42 -0
  39. data/lib/delayed/periodic.rb +81 -0
  40. data/lib/delayed/pool.rb +335 -0
  41. data/lib/delayed/settings.rb +32 -0
  42. data/lib/delayed/version.rb +3 -0
  43. data/lib/delayed/worker.rb +213 -0
  44. data/lib/delayed/yaml_extensions.rb +63 -0
  45. data/lib/delayed_job.rb +40 -0
  46. data/spec/active_record_job_spec.rb +61 -0
  47. data/spec/gemfiles/32.gemfile +6 -0
  48. data/spec/gemfiles/40.gemfile +6 -0
  49. data/spec/gemfiles/41.gemfile +6 -0
  50. data/spec/gemfiles/42.gemfile +6 -0
  51. data/spec/migrate/20140924140513_add_story_table.rb +7 -0
  52. data/spec/redis_job_spec.rb +77 -0
  53. data/spec/sample_jobs.rb +26 -0
  54. data/spec/shared/delayed_batch.rb +85 -0
  55. data/spec/shared/delayed_method.rb +419 -0
  56. data/spec/shared/performable_method.rb +52 -0
  57. data/spec/shared/shared_backend.rb +836 -0
  58. data/spec/shared/worker.rb +291 -0
  59. data/spec/shared_jobs_specs.rb +13 -0
  60. data/spec/spec_helper.rb +91 -0
  61. metadata +329 -0
@@ -0,0 +1,291 @@
1
+ shared_examples_for 'Delayed::Worker' do
2
+ def job_create(opts = {})
3
+ Delayed::Job.create({:payload_object => SimpleJob.new, :queue => Delayed::Settings.queue}.merge(opts))
4
+ end
5
+ def worker_create(opts = {})
6
+ Delayed::Worker.new(opts.merge(:max_priority => nil, :min_priority => nil, :quiet => true))
7
+ end
8
+
9
+ before(:each) do
10
+ @worker = worker_create
11
+ SimpleJob.runs = 0
12
+ Delayed::Worker.on_max_failures = nil
13
+ Delayed::Settings.sleep_delay = ->{ 0.01 }
14
+ end
15
+
16
+ describe "running a job" do
17
+ it "should not fail when running a job with a % in the name" do
18
+ @job = "Some % Name here".send_later_enqueue_args(:starts_with?, { no_delay: true }, "Some % Name")
19
+ @worker.perform(@job)
20
+ end
21
+ end
22
+
23
+ describe "running a batch" do
24
+ context "serially" do
25
+ before do
26
+ @runs = 0
27
+ Delayed::Worker.lifecycle.after(:perform) { @runs += 1 }
28
+ end
29
+
30
+ after do
31
+ Delayed::Worker.lifecycle.reset!
32
+ end
33
+
34
+ it "should run each job in order" do
35
+ bar = "bar"
36
+ expect(bar).to receive(:scan).with("b").ordered
37
+ expect(bar).to receive(:scan).with("a").ordered
38
+ expect(bar).to receive(:scan).with("r").ordered
39
+ batch = Delayed::Batch::PerformableBatch.new(:serial, [
40
+ { :payload_object => Delayed::PerformableMethod.new(bar, :scan, ["b"]) },
41
+ { :payload_object => Delayed::PerformableMethod.new(bar, :scan, ["a"]) },
42
+ { :payload_object => Delayed::PerformableMethod.new(bar, :scan, ["r"]) },
43
+ ])
44
+
45
+ batch_job = Delayed::Job.create :payload_object => batch
46
+ @worker.perform(batch_job).should == 3
47
+ expect(@runs).to eql 4 # batch, plus all jobs
48
+ end
49
+
50
+ it "should succeed regardless of the success/failure of its component jobs" do
51
+ change_setting(Delayed::Settings, :max_attempts, 2) do
52
+ batch = Delayed::Batch::PerformableBatch.new(:serial, [
53
+ { :payload_object => Delayed::PerformableMethod.new("foo", :reverse, []) },
54
+ { :payload_object => Delayed::PerformableMethod.new(1, :/, [0]) },
55
+ { :payload_object => Delayed::PerformableMethod.new("bar", :scan, ["r"]) },
56
+ ])
57
+ batch_job = Delayed::Job.create :payload_object => batch
58
+
59
+ @worker.perform(batch_job).should == 3
60
+ expect(@runs).to eql 3 # batch, plus two successful jobs
61
+
62
+ to_retry = Delayed::Job.list_jobs(:future, 100)
63
+ to_retry.size.should eql 1
64
+ to_retry[0].payload_object.method.should eql :/
65
+ to_retry[0].last_error.should =~ /divided by 0/
66
+ to_retry[0].attempts.should == 1
67
+ end
68
+ end
69
+
70
+ it "should retry a failed individual job" do
71
+ batch = Delayed::Batch::PerformableBatch.new(:serial, [
72
+ { :payload_object => Delayed::PerformableMethod.new(1, :/, [0]) },
73
+ ])
74
+ batch_job = Delayed::Job.create :payload_object => batch
75
+
76
+ expect_any_instance_of(Delayed::Job).to receive(:reschedule).once
77
+ @worker.perform(batch_job).should == 1
78
+ expect(@runs).to eql 1 # just the batch
79
+ end
80
+ end
81
+ end
82
+
83
+ context "worker prioritization" do
84
+ before(:each) do
85
+ @worker = Delayed::Worker.new(:max_priority => 5, :min_priority => 2, :quiet => true)
86
+ end
87
+
88
+ it "should only run jobs that are >= min_priority" do
89
+ SimpleJob.runs.should == 0
90
+
91
+ job_create(:priority => 1)
92
+ job_create(:priority => 3)
93
+ @worker.run
94
+
95
+ SimpleJob.runs.should == 1
96
+ end
97
+
98
+ it "should only run jobs that are <= max_priority" do
99
+ SimpleJob.runs.should == 0
100
+
101
+ job_create(:priority => 10)
102
+ job_create(:priority => 4)
103
+
104
+ @worker.run
105
+
106
+ SimpleJob.runs.should == 1
107
+ end
108
+ end
109
+
110
+ context "while running with locked jobs" do
111
+ before(:each) do
112
+ @worker.name = 'worker1'
113
+ end
114
+
115
+ it "should not run jobs locked by another worker" do
116
+ job_create(:locked_by => 'other_worker', :locked_at => (Delayed::Job.db_time_now - 1.minutes))
117
+ lambda { @worker.run }.should_not change { SimpleJob.runs }
118
+ end
119
+
120
+ it "should run open jobs" do
121
+ job_create
122
+ lambda { @worker.run }.should change { SimpleJob.runs }.from(0).to(1)
123
+ end
124
+ end
125
+
126
+ describe "failed jobs" do
127
+ before do
128
+ # reset defaults
129
+ Delayed::Settings.max_attempts = 25
130
+ @job = Delayed::Job.enqueue ErrorJob.new
131
+ end
132
+
133
+ it "should record last_error when destroy_failed_jobs = false, max_attempts = 1" do
134
+ Delayed::Worker.on_max_failures = proc { false }
135
+ @job.max_attempts = 1
136
+ @job.save!
137
+ (job = Delayed::Job.get_and_lock_next_available('w1')).should == @job
138
+ @worker.perform(job)
139
+ old_id = @job.id
140
+ @job = Delayed::Job.list_jobs(:failed, 1).first
141
+ @job.original_job_id.should == old_id
142
+ @job.last_error.should =~ /did not work/
143
+ @job.last_error.should =~ /shared\/worker.rb/
144
+ @job.attempts.should == 1
145
+ @job.failed_at.should_not be_nil
146
+ @job.run_at.should > Delayed::Job.db_time_now - 10.minutes
147
+ @job.run_at.should < Delayed::Job.db_time_now + 10.minutes
148
+ # job stays locked after failing, for record keeping of time/worker
149
+ @job.should be_locked
150
+
151
+ Delayed::Job.find_available(100, @job.queue).should == []
152
+ end
153
+
154
+ it "should re-schedule jobs after failing" do
155
+ @worker.perform(@job)
156
+ @job = Delayed::Job.find(@job.id)
157
+ @job.last_error.should =~ /did not work/
158
+ @job.last_error.should =~ /sample_jobs.rb:8:in `perform'/
159
+ @job.attempts.should == 1
160
+ @job.run_at.should > Delayed::Job.db_time_now - 10.minutes
161
+ @job.run_at.should < Delayed::Job.db_time_now + 10.minutes
162
+ end
163
+
164
+ it "should notify jobs on failure" do
165
+ ErrorJob.failure_runs = 0
166
+ @worker.perform(@job)
167
+ ErrorJob.failure_runs.should == 1
168
+ end
169
+
170
+ it "should notify jobs on permanent failure" do
171
+ (Delayed::Settings.max_attempts - 1).times { @job.reschedule }
172
+ ErrorJob.permanent_failure_runs = 0
173
+ @worker.perform(@job)
174
+ ErrorJob.permanent_failure_runs.should == 1
175
+ end
176
+ end
177
+
178
+ context "reschedule" do
179
+ before do
180
+ @job = Delayed::Job.create :payload_object => SimpleJob.new
181
+ end
182
+
183
+ context "and we want to destroy jobs" do
184
+ it "should be destroyed if it failed more than Settings.max_attempts times" do
185
+ expect(@job).to receive(:destroy)
186
+ Delayed::Settings.max_attempts.times { @job.reschedule }
187
+ end
188
+
189
+ it "should not be destroyed if failed fewer than Settings.max_attempts times" do
190
+ expect(@job).to receive(:destroy).never
191
+ (Delayed::Settings.max_attempts - 1).times { @job.reschedule }
192
+ end
193
+
194
+ it "should be destroyed if failed more than Job#max_attempts times" do
195
+ Delayed::Settings.max_attempts = 25
196
+ expect(@job).to receive(:destroy)
197
+ @job.max_attempts = 2
198
+ @job.save!
199
+ 2.times { @job.reschedule }
200
+ end
201
+ end
202
+
203
+ context "and we don't want to destroy jobs" do
204
+ before do
205
+ Delayed::Worker.on_max_failures = proc { false }
206
+ end
207
+
208
+ after do
209
+ Delayed::Worker.on_max_failures = nil
210
+ end
211
+
212
+ it "should be failed if it failed more than Settings.max_attempts times" do
213
+ @job.failed_at.should == nil
214
+ Delayed::Settings.max_attempts.times { @job.reschedule }
215
+ Delayed::Job.list_jobs(:failed, 100).size.should == 1
216
+ end
217
+
218
+ it "should not be failed if it failed fewer than Settings.max_attempts times" do
219
+ (Delayed::Settings.max_attempts - 1).times { @job.reschedule }
220
+ @job = Delayed::Job.find(@job.id)
221
+ @job.failed_at.should == nil
222
+ end
223
+
224
+ end
225
+
226
+ context "and we give an on_max_failures callback" do
227
+ it "should be failed max_attempts times and cb is false" do
228
+ Delayed::Worker.on_max_failures = proc do |job, ex|
229
+ job.should == @job
230
+ false
231
+ end
232
+ expect(@job).to receive(:fail!)
233
+ Delayed::Settings.max_attempts.times { @job.reschedule }
234
+ end
235
+
236
+ it "should be destroyed if it failed max_attempts times and cb is true" do
237
+ Delayed::Worker.on_max_failures = proc do |job, ex|
238
+ job.should == @job
239
+ true
240
+ end
241
+ expect(@job).to receive(:destroy)
242
+ Delayed::Settings.max_attempts.times { @job.reschedule }
243
+ end
244
+ end
245
+ end
246
+
247
+
248
+ context "Queue workers" do
249
+ before :each do
250
+ Delayed::Settings.queue = "Queue workers test"
251
+ job_create(:queue => 'queue1')
252
+ job_create(:queue => 'queue2')
253
+ end
254
+
255
+ it "should only work off jobs assigned to themselves" do
256
+ worker = worker_create(:queue=>'queue1')
257
+ SimpleJob.runs.should == 0
258
+ worker.run
259
+ SimpleJob.runs.should == 1
260
+
261
+ SimpleJob.runs = 0
262
+
263
+ worker = worker_create(:queue=>'queue2')
264
+ SimpleJob.runs.should == 0
265
+ worker.run
266
+ SimpleJob.runs.should == 1
267
+ end
268
+
269
+ it "should not work off jobs not assigned to themselves" do
270
+ worker = worker_create(:queue=>'queue3')
271
+
272
+ SimpleJob.runs.should == 0
273
+ worker.run
274
+ SimpleJob.runs.should == 0
275
+ end
276
+
277
+ it "should get the default queue if none is set" do
278
+ queue_name = "default_queue"
279
+ Delayed::Settings.queue = queue_name
280
+ worker = worker_create(:queue=>nil)
281
+ worker.queue.should == queue_name
282
+ end
283
+
284
+ it "should override default queue name if specified in initialize" do
285
+ queue_name = "my_queue"
286
+ Delayed::Settings.queue = "default_queue"
287
+ worker = worker_create(:queue=>queue_name)
288
+ worker.queue.should == queue_name
289
+ end
290
+ end
291
+ end
@@ -0,0 +1,13 @@
1
+ require File.expand_path('../shared/shared_backend', __FILE__)
2
+ require File.expand_path('../shared/delayed_batch', __FILE__)
3
+ require File.expand_path('../shared/delayed_method', __FILE__)
4
+ require File.expand_path('../shared/performable_method', __FILE__)
5
+ require File.expand_path('../shared/worker', __FILE__)
6
+
7
+ shared_examples_for 'a delayed_jobs implementation' do
8
+ include_examples 'a backend'
9
+ include_examples 'Delayed::Batch'
10
+ include_examples 'random ruby objects'
11
+ include_examples 'Delayed::PerformableMethod'
12
+ include_examples 'Delayed::Worker'
13
+ end
@@ -0,0 +1,91 @@
1
+ require 'delayed_job'
2
+
3
+ require 'database_cleaner'
4
+ require 'test_after_commit'
5
+ require 'timecop'
6
+ require 'pry'
7
+
8
+ RSpec.configure do |config|
9
+
10
+ config.expect_with(:rspec) do |c|
11
+ c.syntax = [:should, :expect]
12
+ end
13
+
14
+ config.before(:suite) do
15
+ DatabaseCleaner.strategy = :transaction
16
+ DatabaseCleaner.clean_with(:truncation)
17
+ end
18
+
19
+ config.around(:each) do |example|
20
+ if Delayed::Backend::Redis::Job.redis
21
+ Delayed::Backend::Redis::Job.redis.flushdb
22
+ end
23
+ DatabaseCleaner.cleaning do
24
+ example.run
25
+ end
26
+ end
27
+
28
+ end
29
+
30
+ ENV['TEST_ENV_NUMBER'] ||= '1'
31
+ ENV['TEST_DB_HOST'] ||= 'localhost'
32
+ ENV['TEST_DB_DATABASE'] ||= "canvas-jobs-test-#{ENV['TEST_ENV_NUMBER']}"
33
+ ENV['TEST_REDIS_CONNECTION'] ||= 'redis://localhost:6379/'
34
+
35
+ Delayed::Backend::Redis::Job.redis = Redis.new(url: ENV['TEST_REDIS_CONNECTION'])
36
+
37
+ ActiveRecord::Base.establish_connection({
38
+ adapter: :postgresql,
39
+ host: ENV['TEST_DB_HOST'],
40
+ encoding: 'utf8',
41
+ username: ENV['TEST_DB_USERNAME'],
42
+ database: ENV['TEST_DB_DATABASE'],
43
+ })
44
+ # TODO reset db and migrate again, to test migrations
45
+
46
+ ActiveRecord::Migrator.migrate("db/migrate")
47
+ ActiveRecord::Migrator.migrate("spec/migrate")
48
+
49
+ Time.zone = 'UTC'
50
+ Rails.logger = Logger.new(nil)
51
+
52
+ # Purely useful for test cases...
53
+ class Story < ActiveRecord::Base
54
+ def tell; text; end
55
+ def whatever(n, _); tell*n; end
56
+ def whatever_else(n, _); tell*n; end
57
+
58
+ handle_asynchronously :whatever
59
+ handle_asynchronously_with_queue :whatever_else, "testqueue"
60
+ end
61
+
62
+ class StoryReader
63
+ def read(story)
64
+ "Epilog: #{story.tell}"
65
+ end
66
+
67
+ def self.reverse(str)
68
+ str.reverse
69
+ end
70
+ end
71
+
72
+ module MyReverser
73
+ def self.reverse(str)
74
+ str.reverse
75
+ end
76
+ end
77
+
78
+ def change_setting(klass, setting_name, value)
79
+ old_val = klass.class_variable_get(:"@@#{setting_name}")
80
+ klass.send("#{setting_name}=", value)
81
+ yield
82
+ ensure
83
+ klass.send("#{setting_name}=", old_val)
84
+ end
85
+
86
+ def run_job(job)
87
+ Delayed::Worker.new.perform(job)
88
+ end
89
+
90
+ require File.expand_path('../sample_jobs', __FILE__)
91
+ require File.expand_path('../shared_jobs_specs', __FILE__)
metadata ADDED
@@ -0,0 +1,329 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: canvas-jobs
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.0
5
+ platform: ruby
6
+ authors:
7
+ - Tobias Luetke
8
+ - Brian Palmer
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-09-30 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: after_transaction_commit
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - '='
19
+ - !ruby/object:Gem::Version
20
+ version: 1.0.1
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - '='
26
+ - !ruby/object:Gem::Version
27
+ version: 1.0.1
28
+ - !ruby/object:Gem::Dependency
29
+ name: rails
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '3.2'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '3.2'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rufus-scheduler
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - '='
47
+ - !ruby/object:Gem::Version
48
+ version: 2.0.6
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - '='
54
+ - !ruby/object:Gem::Version
55
+ version: 2.0.6
56
+ - !ruby/object:Gem::Dependency
57
+ name: redis
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">"
61
+ - !ruby/object:Gem::Version
62
+ version: '3.0'
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">"
68
+ - !ruby/object:Gem::Version
69
+ version: '3.0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: redis-scripting
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - '='
75
+ - !ruby/object:Gem::Version
76
+ version: 1.0.1
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - '='
82
+ - !ruby/object:Gem::Version
83
+ version: 1.0.1
84
+ - !ruby/object:Gem::Dependency
85
+ name: syck
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :runtime
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: bump
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: database_cleaner
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: pg
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ type: :development
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ - !ruby/object:Gem::Dependency
141
+ name: pry
142
+ requirement: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ type: :development
148
+ prerelease: false
149
+ version_requirements: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ - !ruby/object:Gem::Dependency
155
+ name: rake
156
+ requirement: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ version: '0'
161
+ type: :development
162
+ prerelease: false
163
+ version_requirements: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
168
+ - !ruby/object:Gem::Dependency
169
+ name: rspec
170
+ requirement: !ruby/object:Gem::Requirement
171
+ requirements:
172
+ - - ">="
173
+ - !ruby/object:Gem::Version
174
+ version: '0'
175
+ type: :development
176
+ prerelease: false
177
+ version_requirements: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - ">="
180
+ - !ruby/object:Gem::Version
181
+ version: '0'
182
+ - !ruby/object:Gem::Dependency
183
+ name: test_after_commit
184
+ requirement: !ruby/object:Gem::Requirement
185
+ requirements:
186
+ - - ">="
187
+ - !ruby/object:Gem::Version
188
+ version: '0'
189
+ type: :development
190
+ prerelease: false
191
+ version_requirements: !ruby/object:Gem::Requirement
192
+ requirements:
193
+ - - ">="
194
+ - !ruby/object:Gem::Version
195
+ version: '0'
196
+ - !ruby/object:Gem::Dependency
197
+ name: timecop
198
+ requirement: !ruby/object:Gem::Requirement
199
+ requirements:
200
+ - - ">="
201
+ - !ruby/object:Gem::Version
202
+ version: '0'
203
+ type: :development
204
+ prerelease: false
205
+ version_requirements: !ruby/object:Gem::Requirement
206
+ requirements:
207
+ - - ">="
208
+ - !ruby/object:Gem::Version
209
+ version: '0'
210
+ - !ruby/object:Gem::Dependency
211
+ name: wwtd
212
+ requirement: !ruby/object:Gem::Requirement
213
+ requirements:
214
+ - - ">="
215
+ - !ruby/object:Gem::Version
216
+ version: '0'
217
+ type: :development
218
+ prerelease: false
219
+ version_requirements: !ruby/object:Gem::Requirement
220
+ requirements:
221
+ - - ">="
222
+ - !ruby/object:Gem::Version
223
+ version: '0'
224
+ description:
225
+ email:
226
+ - brianp@instructure.com
227
+ executables: []
228
+ extensions: []
229
+ extra_rdoc_files: []
230
+ files:
231
+ - db/migrate/20101216224513_create_delayed_jobs.rb
232
+ - db/migrate/20110208031356_add_delayed_jobs_tag.rb
233
+ - db/migrate/20110426161613_add_delayed_jobs_max_attempts.rb
234
+ - db/migrate/20110516225834_add_delayed_jobs_strand.rb
235
+ - db/migrate/20110531144916_cleanup_delayed_jobs_indexes.rb
236
+ - db/migrate/20110610213249_optimize_delayed_jobs.rb
237
+ - db/migrate/20110831210257_add_delayed_jobs_next_in_strand.rb
238
+ - db/migrate/20120510004759_delayed_jobs_delete_trigger_lock_for_update.rb
239
+ - db/migrate/20120531150712_drop_psql_jobs_pop_fn.rb
240
+ - db/migrate/20120607164022_delayed_jobs_use_advisory_locks.rb
241
+ - db/migrate/20120607181141_index_jobs_on_locked_by.rb
242
+ - db/migrate/20120608191051_add_jobs_run_at_index.rb
243
+ - db/migrate/20120927184213_change_delayed_jobs_handler_to_text.rb
244
+ - db/migrate/20140505215131_add_failed_jobs_original_job_id.rb
245
+ - db/migrate/20140505215510_copy_failed_jobs_original_id.rb
246
+ - db/migrate/20140505223637_drop_failed_jobs_original_id.rb
247
+ - db/migrate/20140512213941_add_source_to_jobs.rb
248
+ - lib/canvas-jobs.rb
249
+ - lib/delayed/backend/active_record.rb
250
+ - lib/delayed/backend/base.rb
251
+ - lib/delayed/backend/redis/bulk_update.lua
252
+ - lib/delayed/backend/redis/destroy_job.lua
253
+ - lib/delayed/backend/redis/enqueue.lua
254
+ - lib/delayed/backend/redis/fail_job.lua
255
+ - lib/delayed/backend/redis/find_available.lua
256
+ - lib/delayed/backend/redis/functions.rb
257
+ - lib/delayed/backend/redis/get_and_lock_next_available.lua
258
+ - lib/delayed/backend/redis/includes/jobs_common.lua
259
+ - lib/delayed/backend/redis/job.rb
260
+ - lib/delayed/backend/redis/set_running.lua
261
+ - lib/delayed/backend/redis/tickle_strand.lua
262
+ - lib/delayed/batch.rb
263
+ - lib/delayed/engine.rb
264
+ - lib/delayed/job_tracking.rb
265
+ - lib/delayed/lifecycle.rb
266
+ - lib/delayed/message_sending.rb
267
+ - lib/delayed/performable_method.rb
268
+ - lib/delayed/periodic.rb
269
+ - lib/delayed/pool.rb
270
+ - lib/delayed/settings.rb
271
+ - lib/delayed/version.rb
272
+ - lib/delayed/worker.rb
273
+ - lib/delayed/yaml_extensions.rb
274
+ - lib/delayed_job.rb
275
+ - spec/active_record_job_spec.rb
276
+ - spec/gemfiles/32.gemfile
277
+ - spec/gemfiles/40.gemfile
278
+ - spec/gemfiles/41.gemfile
279
+ - spec/gemfiles/42.gemfile
280
+ - spec/migrate/20140924140513_add_story_table.rb
281
+ - spec/redis_job_spec.rb
282
+ - spec/sample_jobs.rb
283
+ - spec/shared/delayed_batch.rb
284
+ - spec/shared/delayed_method.rb
285
+ - spec/shared/performable_method.rb
286
+ - spec/shared/shared_backend.rb
287
+ - spec/shared/worker.rb
288
+ - spec/shared_jobs_specs.rb
289
+ - spec/spec_helper.rb
290
+ homepage: http://www.instructure.com
291
+ licenses: []
292
+ metadata: {}
293
+ post_install_message:
294
+ rdoc_options: []
295
+ require_paths:
296
+ - lib
297
+ required_ruby_version: !ruby/object:Gem::Requirement
298
+ requirements:
299
+ - - ">="
300
+ - !ruby/object:Gem::Version
301
+ version: '0'
302
+ required_rubygems_version: !ruby/object:Gem::Requirement
303
+ requirements:
304
+ - - ">="
305
+ - !ruby/object:Gem::Version
306
+ version: '0'
307
+ requirements: []
308
+ rubyforge_project:
309
+ rubygems_version: 2.4.1
310
+ signing_key:
311
+ specification_version: 4
312
+ summary: Instructure-maintained fork of delayed_job
313
+ test_files:
314
+ - spec/active_record_job_spec.rb
315
+ - spec/gemfiles/32.gemfile
316
+ - spec/gemfiles/40.gemfile
317
+ - spec/gemfiles/41.gemfile
318
+ - spec/gemfiles/42.gemfile
319
+ - spec/migrate/20140924140513_add_story_table.rb
320
+ - spec/redis_job_spec.rb
321
+ - spec/sample_jobs.rb
322
+ - spec/shared/delayed_batch.rb
323
+ - spec/shared/delayed_method.rb
324
+ - spec/shared/performable_method.rb
325
+ - spec/shared/shared_backend.rb
326
+ - spec/shared/worker.rb
327
+ - spec/shared_jobs_specs.rb
328
+ - spec/spec_helper.rb
329
+ has_rdoc: