inst-jobs 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +7 -0
  2. data/bin/inst_job +4 -0
  3. data/db/migrate/20101216224513_create_delayed_jobs.rb +40 -0
  4. data/db/migrate/20110208031356_add_delayed_jobs_tag.rb +14 -0
  5. data/db/migrate/20110426161613_add_delayed_jobs_max_attempts.rb +13 -0
  6. data/db/migrate/20110516225834_add_delayed_jobs_strand.rb +14 -0
  7. data/db/migrate/20110531144916_cleanup_delayed_jobs_indexes.rb +26 -0
  8. data/db/migrate/20110610213249_optimize_delayed_jobs.rb +40 -0
  9. data/db/migrate/20110831210257_add_delayed_jobs_next_in_strand.rb +52 -0
  10. data/db/migrate/20120510004759_delayed_jobs_delete_trigger_lock_for_update.rb +31 -0
  11. data/db/migrate/20120531150712_drop_psql_jobs_pop_fn.rb +15 -0
  12. data/db/migrate/20120607164022_delayed_jobs_use_advisory_locks.rb +80 -0
  13. data/db/migrate/20120607181141_index_jobs_on_locked_by.rb +15 -0
  14. data/db/migrate/20120608191051_add_jobs_run_at_index.rb +15 -0
  15. data/db/migrate/20120927184213_change_delayed_jobs_handler_to_text.rb +13 -0
  16. data/db/migrate/20140505215131_add_failed_jobs_original_job_id.rb +13 -0
  17. data/db/migrate/20140505215510_copy_failed_jobs_original_id.rb +13 -0
  18. data/db/migrate/20140505223637_drop_failed_jobs_original_id.rb +13 -0
  19. data/db/migrate/20140512213941_add_source_to_jobs.rb +15 -0
  20. data/db/migrate/20150807133223_add_max_concurrent_to_jobs.rb +70 -0
  21. data/db/migrate/20151123210429_add_expires_at_to_jobs.rb +15 -0
  22. data/db/migrate/20151210162949_improve_max_concurrent.rb +50 -0
  23. data/lib/delayed/backend/active_record.rb +340 -0
  24. data/lib/delayed/backend/base.rb +335 -0
  25. data/lib/delayed/backend/redis/bulk_update.lua +50 -0
  26. data/lib/delayed/backend/redis/destroy_job.lua +2 -0
  27. data/lib/delayed/backend/redis/enqueue.lua +29 -0
  28. data/lib/delayed/backend/redis/fail_job.lua +5 -0
  29. data/lib/delayed/backend/redis/find_available.lua +3 -0
  30. data/lib/delayed/backend/redis/functions.rb +57 -0
  31. data/lib/delayed/backend/redis/get_and_lock_next_available.lua +17 -0
  32. data/lib/delayed/backend/redis/includes/jobs_common.lua +203 -0
  33. data/lib/delayed/backend/redis/job.rb +497 -0
  34. data/lib/delayed/backend/redis/set_running.lua +5 -0
  35. data/lib/delayed/backend/redis/tickle_strand.lua +2 -0
  36. data/lib/delayed/batch.rb +56 -0
  37. data/lib/delayed/cli.rb +101 -0
  38. data/lib/delayed/daemon.rb +103 -0
  39. data/lib/delayed/engine.rb +4 -0
  40. data/lib/delayed/job_tracking.rb +31 -0
  41. data/lib/delayed/lifecycle.rb +90 -0
  42. data/lib/delayed/log_tailer.rb +22 -0
  43. data/lib/delayed/message_sending.rb +134 -0
  44. data/lib/delayed/performable_method.rb +52 -0
  45. data/lib/delayed/periodic.rb +85 -0
  46. data/lib/delayed/plugin.rb +22 -0
  47. data/lib/delayed/pool.rb +161 -0
  48. data/lib/delayed/server/helpers.rb +28 -0
  49. data/lib/delayed/server/public/css/app.css +12 -0
  50. data/lib/delayed/server/public/js/app.js +132 -0
  51. data/lib/delayed/server/views/index.erb +90 -0
  52. data/lib/delayed/server/views/layout.erb +47 -0
  53. data/lib/delayed/server.rb +120 -0
  54. data/lib/delayed/settings.rb +90 -0
  55. data/lib/delayed/testing.rb +32 -0
  56. data/lib/delayed/version.rb +3 -0
  57. data/lib/delayed/work_queue/in_process.rb +13 -0
  58. data/lib/delayed/work_queue/parent_process.rb +180 -0
  59. data/lib/delayed/worker.rb +234 -0
  60. data/lib/delayed/yaml_extensions.rb +109 -0
  61. data/lib/delayed_job.rb +46 -0
  62. data/lib/inst-jobs.rb +1 -0
  63. data/spec/active_record_job_spec.rb +246 -0
  64. data/spec/delayed/cli_spec.rb +23 -0
  65. data/spec/delayed/daemon_spec.rb +35 -0
  66. data/spec/delayed/server_spec.rb +63 -0
  67. data/spec/delayed/settings_spec.rb +32 -0
  68. data/spec/delayed/work_queue/in_process_spec.rb +31 -0
  69. data/spec/delayed/work_queue/parent_process_spec.rb +159 -0
  70. data/spec/delayed/worker_spec.rb +16 -0
  71. data/spec/gemfiles/32.gemfile +6 -0
  72. data/spec/gemfiles/40.gemfile +5 -0
  73. data/spec/gemfiles/41.gemfile +5 -0
  74. data/spec/gemfiles/42.gemfile +5 -0
  75. data/spec/migrate/20140924140513_add_story_table.rb +7 -0
  76. data/spec/redis_job_spec.rb +140 -0
  77. data/spec/sample_jobs.rb +28 -0
  78. data/spec/shared/delayed_batch.rb +85 -0
  79. data/spec/shared/delayed_method.rb +419 -0
  80. data/spec/shared/performable_method.rb +66 -0
  81. data/spec/shared/shared_backend.rb +819 -0
  82. data/spec/shared/testing.rb +48 -0
  83. data/spec/shared/worker.rb +378 -0
  84. data/spec/shared_jobs_specs.rb +15 -0
  85. data/spec/spec_helper.rb +97 -0
  86. metadata +390 -0
@@ -0,0 +1,48 @@
1
+ shared_examples_for 'Delayed::Testing' do
2
+ class TestingWorker
3
+ cattr_accessor :runs
4
+
5
+ def self.run
6
+ self.runs += 1
7
+ end
8
+ end
9
+
10
+ before do
11
+ TestingWorker.runs = 0
12
+ end
13
+
14
+ describe '.run_job' do
15
+ it 'should run a single queued job' do
16
+ job = TestingWorker.send_later_enqueue_args(:run, no_delay: true)
17
+ Delayed::Testing.run_job(job)
18
+ expect(TestingWorker.runs).to eq 1
19
+ end
20
+ end
21
+
22
+ describe '.drain' do
23
+ it 'should run all queued jobs' do
24
+ 3.times { TestingWorker.send_later(:run) }
25
+ YAML.dump(TestingWorker)
26
+ Delayed::Testing.drain
27
+ expect(TestingWorker.runs).to eq 3
28
+ end
29
+ end
30
+
31
+ describe 'track_created' do
32
+ it 'should return the list of jobs created in the block' do
33
+ 3.times { TestingWorker.send_later(:run) }
34
+ jobs = Delayed::Testing.track_created { 2.times { TestingWorker.send_later(:run) } }
35
+ expect(jobs.size).to eq 2
36
+ expect(jobs.first.tag).to eq "TestingWorker.run"
37
+ end
38
+ end
39
+
40
+ describe 'clear_all!' do
41
+ it 'should delete all queued jobs' do
42
+ 3.times { TestingWorker.send_later(:run) }
43
+ Delayed::Testing.clear_all!
44
+ Delayed::Testing.drain
45
+ expect(TestingWorker.runs).to eq 0
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,378 @@
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
+ it "should not run jobs locked by another worker" do
112
+ job_create(:locked_by => 'other_worker', :locked_at => (Delayed::Job.db_time_now - 1.minutes))
113
+ lambda { @worker.run }.should_not change { SimpleJob.runs }
114
+ end
115
+
116
+ it "should run open jobs" do
117
+ job_create
118
+ lambda { @worker.run }.should change { SimpleJob.runs }.from(0).to(1)
119
+ end
120
+ end
121
+
122
+ describe "failed jobs" do
123
+ before do
124
+ # reset defaults
125
+ Delayed::Settings.max_attempts = 25
126
+ @job = Delayed::Job.enqueue ErrorJob.new
127
+ end
128
+
129
+ it "should record last_error when destroy_failed_jobs = false, max_attempts = 1" do
130
+ Delayed::Worker.on_max_failures = proc { false }
131
+ @job.max_attempts = 1
132
+ @job.save!
133
+ (job = Delayed::Job.get_and_lock_next_available('w1')).should == @job
134
+ @worker.perform(job)
135
+ old_id = @job.id
136
+ @job = Delayed::Job.list_jobs(:failed, 1).first
137
+ @job.original_job_id.should == old_id
138
+ @job.last_error.should =~ /did not work/
139
+ @job.last_error.should =~ /shared\/worker.rb/
140
+ @job.attempts.should == 1
141
+ @job.failed_at.should_not be_nil
142
+ @job.run_at.should > Delayed::Job.db_time_now - 10.minutes
143
+ @job.run_at.should < Delayed::Job.db_time_now + 10.minutes
144
+ # job stays locked after failing, for record keeping of time/worker
145
+ @job.should be_locked
146
+
147
+ Delayed::Job.find_available(100, @job.queue).should == []
148
+ end
149
+
150
+ it "should re-schedule jobs after failing" do
151
+ @worker.perform(@job)
152
+ @job = Delayed::Job.find(@job.id)
153
+ @job.last_error.should =~ /did not work/
154
+ @job.last_error.should =~ /sample_jobs.rb:8:in `perform'/
155
+ @job.attempts.should == 1
156
+ @job.run_at.should > Delayed::Job.db_time_now - 10.minutes
157
+ @job.run_at.should < Delayed::Job.db_time_now + 10.minutes
158
+ end
159
+
160
+ it "should notify jobs on failure" do
161
+ ErrorJob.failure_runs = 0
162
+ @worker.perform(@job)
163
+ ErrorJob.failure_runs.should == 1
164
+ end
165
+
166
+ it "should notify jobs on permanent failure" do
167
+ (Delayed::Settings.max_attempts - 1).times { @job.reschedule }
168
+ ErrorJob.permanent_failure_runs = 0
169
+ @worker.perform(@job)
170
+ ErrorJob.permanent_failure_runs.should == 1
171
+ end
172
+ end
173
+
174
+ context "reschedule" do
175
+ before do
176
+ @job = Delayed::Job.create :payload_object => SimpleJob.new
177
+ end
178
+
179
+ context "and we want to destroy jobs" do
180
+ it "should be destroyed if it failed more than Settings.max_attempts times" do
181
+ expect(@job).to receive(:destroy)
182
+ Delayed::Settings.max_attempts.times { @job.reschedule }
183
+ end
184
+
185
+ it "should not be destroyed if failed fewer than Settings.max_attempts times" do
186
+ expect(@job).to receive(:destroy).never
187
+ (Delayed::Settings.max_attempts - 1).times { @job.reschedule }
188
+ end
189
+
190
+ it "should be destroyed if failed more than Job#max_attempts times" do
191
+ Delayed::Settings.max_attempts = 25
192
+ expect(@job).to receive(:destroy)
193
+ @job.max_attempts = 2
194
+ @job.save!
195
+ 2.times { @job.reschedule }
196
+ end
197
+
198
+ it "should be destroyed if it has expired" do
199
+ job = Delayed::Job.create :payload_object => SimpleJob.new, :expires_at => Delayed::Job.db_time_now - 1.day
200
+ expect(job).to receive(:destroy)
201
+ job.reschedule
202
+ end
203
+ end
204
+
205
+ context "and we don't want to destroy jobs" do
206
+ before do
207
+ Delayed::Worker.on_max_failures = proc { false }
208
+ end
209
+
210
+ after do
211
+ Delayed::Worker.on_max_failures = nil
212
+ end
213
+
214
+ it "should be failed if it failed more than Settings.max_attempts times" do
215
+ @job.failed_at.should == nil
216
+ Delayed::Settings.max_attempts.times { @job.reschedule }
217
+ Delayed::Job.list_jobs(:failed, 100).size.should == 1
218
+ end
219
+
220
+ it "should not be failed if it failed fewer than Settings.max_attempts times" do
221
+ (Delayed::Settings.max_attempts - 1).times { @job.reschedule }
222
+ @job = Delayed::Job.find(@job.id)
223
+ @job.failed_at.should == nil
224
+ end
225
+
226
+ it "should be failed if it has expired" do
227
+ job = Delayed::Job.create :payload_object => SimpleJob.new, :expires_at => Delayed::Job.db_time_now - 1.day
228
+ expect(job).to receive(:fail!)
229
+ job.reschedule
230
+ end
231
+ end
232
+
233
+ context "and we give an on_max_failures callback" do
234
+ it "should be failed max_attempts times and cb is false" do
235
+ Delayed::Worker.on_max_failures = proc do |job, ex|
236
+ job.should == @job
237
+ false
238
+ end
239
+ expect(@job).to receive(:fail!)
240
+ Delayed::Settings.max_attempts.times { @job.reschedule }
241
+ end
242
+
243
+ it "should be destroyed if it failed max_attempts times and cb is true" do
244
+ Delayed::Worker.on_max_failures = proc do |job, ex|
245
+ job.should == @job
246
+ true
247
+ end
248
+ expect(@job).to receive(:destroy)
249
+ Delayed::Settings.max_attempts.times { @job.reschedule }
250
+ end
251
+ end
252
+ end
253
+
254
+
255
+ context "Queue workers" do
256
+ before :each do
257
+ Delayed::Settings.queue = "Queue workers test"
258
+ job_create(:queue => 'queue1')
259
+ job_create(:queue => 'queue2')
260
+ end
261
+
262
+ it "should only work off jobs assigned to themselves" do
263
+ worker = worker_create(:queue=>'queue1')
264
+ SimpleJob.runs.should == 0
265
+ worker.run
266
+ SimpleJob.runs.should == 1
267
+
268
+ SimpleJob.runs = 0
269
+
270
+ worker = worker_create(:queue=>'queue2')
271
+ SimpleJob.runs.should == 0
272
+ worker.run
273
+ SimpleJob.runs.should == 1
274
+ end
275
+
276
+ it "should not work off jobs not assigned to themselves" do
277
+ worker = worker_create(:queue=>'queue3')
278
+
279
+ SimpleJob.runs.should == 0
280
+ worker.run
281
+ SimpleJob.runs.should == 0
282
+ end
283
+
284
+ it "should get the default queue if none is set" do
285
+ queue_name = "default_queue"
286
+ Delayed::Settings.queue = queue_name
287
+ worker = worker_create(:queue=>nil)
288
+ worker.queue_name.should == queue_name
289
+ end
290
+
291
+ it "should override default queue name if specified in initialize" do
292
+ queue_name = "my_queue"
293
+ Delayed::Settings.queue = "default_queue"
294
+ worker = worker_create(:queue=>queue_name)
295
+ worker.queue_name.should == queue_name
296
+ end
297
+ end
298
+
299
+ context "plugins" do
300
+ class TestPlugin < ::Delayed::Plugin
301
+ cattr_accessor :runs
302
+ self.runs = 0
303
+ callbacks do |lifecycle|
304
+ lifecycle.around(:invoke_job) do |job, *args, &block|
305
+ TestPlugin.runs += 1
306
+ block.call(job, *args)
307
+ end
308
+ end
309
+ end
310
+
311
+ it "should create and call the plugin callbacks" do
312
+ TestPlugin.runs = 0
313
+ Delayed::Worker.plugins << TestPlugin
314
+ job_create
315
+ @worker = Delayed::Worker.new(:quiet => true)
316
+ @worker.run
317
+ expect(TestPlugin.runs).to eq(1)
318
+ expect(SimpleJob.runs).to eq(1)
319
+ end
320
+ end
321
+
322
+ describe "expires_at" do
323
+ it "should run non-expired jobs" do
324
+ Delayed::Job.enqueue SimpleJob.new, :expires_at => Delayed::Job.db_time_now + 1.day
325
+ expect { @worker.run }.to change { SimpleJob.runs }.by(1)
326
+ end
327
+
328
+ it "should not run expired jobs" do
329
+ Delayed::Job.enqueue SimpleJob.new, :expires_at => Delayed::Job.db_time_now - 1.day
330
+ expect { @worker.run }.to change { SimpleJob.runs }.by(0)
331
+ end
332
+
333
+ it "should report a permanent failure when an expired job is dequeued" do
334
+ ErrorJob.last_error = nil
335
+ Delayed::Job.enqueue ErrorJob.new, :expires_at => Delayed::Job.db_time_now - 1.day
336
+ expect { @worker.run }.to change { ErrorJob.permanent_failure_runs }.by(1)
337
+ expect(ErrorJob.last_error).to be_a Delayed::Backend::JobExpired
338
+ end
339
+ end
340
+
341
+ describe "send_later_enqueue_args failure callbacks" do
342
+ it "should call the on_failure callback" do
343
+ ErrorJob.last_error = nil
344
+ ErrorJob.new.send_later_enqueue_args(:perform, :max_attempts => 2, :on_failure => :on_failure)
345
+ expect { @worker.run }.to change { ErrorJob.failure_runs }.by(1)
346
+ expect(ErrorJob.last_error.to_s).to eq 'did not work'
347
+ end
348
+
349
+ it "should call the on_permanent_failure callback" do
350
+ ErrorJob.last_error = nil
351
+ ErrorJob.new.send_later_enqueue_args(:perform, :max_attempts => 1, :on_permanent_failure => :on_failure)
352
+ expect { @worker.run }.to change { ErrorJob.failure_runs }.by(1)
353
+ expect(ErrorJob.last_error.to_s).to eq 'did not work'
354
+ end
355
+ end
356
+
357
+ describe "#start" do
358
+ it "fires off an execute callback on the processing jobs loop" do
359
+ fired = false
360
+ expect(@worker).to receive(:run)
361
+ expect(@worker).to receive(:exit?).and_return(true)
362
+ Delayed::Worker.lifecycle.before(:execute) { |w| w == @worker && fired = true }
363
+ @worker.start
364
+ expect(fired).to eq(true)
365
+ end
366
+ end
367
+
368
+ describe "#run" do
369
+ it "fires off a loop callback on each call to run" do
370
+ fired = 0
371
+ Delayed::Worker.lifecycle.before(:loop) { |w| w == @worker && fired += 1 }
372
+ expect(Delayed::Job).to receive(:get_and_lock_next_available).twice.and_return(nil)
373
+ @worker.run
374
+ @worker.run
375
+ expect(fired).to eq(2)
376
+ end
377
+ end
378
+ end
@@ -0,0 +1,15 @@
1
+ require File.expand_path('../shared/delayed_batch', __FILE__)
2
+ require File.expand_path('../shared/delayed_method', __FILE__)
3
+ require File.expand_path('../shared/performable_method', __FILE__)
4
+ require File.expand_path('../shared/shared_backend', __FILE__)
5
+ require File.expand_path('../shared/testing', __FILE__)
6
+ require File.expand_path('../shared/worker', __FILE__)
7
+
8
+ shared_examples_for 'a delayed_jobs implementation' do
9
+ include_examples 'a backend'
10
+ include_examples 'Delayed::Batch'
11
+ include_examples 'random ruby objects'
12
+ include_examples 'Delayed::PerformableMethod'
13
+ include_examples 'Delayed::Worker'
14
+ include_examples 'Delayed::Testing'
15
+ end
@@ -0,0 +1,97 @@
1
+ require 'delayed_job'
2
+ require 'delayed/testing'
3
+
4
+ require 'database_cleaner'
5
+ require 'rack/test'
6
+ require 'test_after_commit'
7
+ require 'timecop'
8
+ require 'pry'
9
+
10
+ RSpec.configure do |config|
11
+
12
+ config.expect_with(:rspec) do |c|
13
+ c.syntax = [:should, :expect]
14
+ end
15
+
16
+ config.before(:suite) do
17
+ DatabaseCleaner.strategy = :transaction
18
+ DatabaseCleaner.clean_with(:truncation)
19
+ end
20
+
21
+ config.before(:each) do |example|
22
+ if Delayed::Backend::Redis::Job.redis
23
+ Delayed::Backend::Redis::Job.redis.flushdb
24
+ end
25
+ DatabaseCleaner.strategy = (example.metadata[:sinatra] ? :truncation : :transaction)
26
+ DatabaseCleaner.start
27
+ end
28
+
29
+ config.after(:each) do
30
+ DatabaseCleaner.clean
31
+ end
32
+ end
33
+
34
+ ENV['TEST_ENV_NUMBER'] ||= '1'
35
+ ENV['TEST_DB_HOST'] ||= 'localhost'
36
+ ENV['TEST_DB_DATABASE'] ||= "inst-jobs-test-#{ENV['TEST_ENV_NUMBER']}"
37
+ ENV['TEST_REDIS_CONNECTION'] ||= 'redis://localhost:6379/'
38
+
39
+ Delayed::Backend::Redis::Job.redis = Redis.new(url: ENV['TEST_REDIS_CONNECTION'])
40
+
41
+ ActiveRecord::Base.establish_connection({
42
+ adapter: :postgresql,
43
+ host: ENV['TEST_DB_HOST'],
44
+ encoding: 'utf8',
45
+ username: ENV['TEST_DB_USERNAME'],
46
+ database: ENV['TEST_DB_DATABASE'],
47
+ })
48
+ # TODO reset db and migrate again, to test migrations
49
+
50
+ ActiveRecord::Migrator.migrate("db/migrate")
51
+ ActiveRecord::Migrator.migrate("spec/migrate")
52
+ Delayed::Backend::ActiveRecord::Job.reset_column_information
53
+ Delayed::Backend::ActiveRecord::Job::Failed.reset_column_information
54
+
55
+ Time.zone = 'UTC'
56
+ Rails.logger = Logger.new(nil)
57
+
58
+ # Purely useful for test cases...
59
+ class Story < ActiveRecord::Base
60
+ def tell; text; end
61
+ def whatever(n, _); tell*n; end
62
+ def whatever_else(n, _); tell*n; end
63
+
64
+ handle_asynchronously :whatever
65
+ handle_asynchronously_with_queue :whatever_else, "testqueue"
66
+ end
67
+
68
+ class StoryReader
69
+ def read(story)
70
+ "Epilog: #{story.tell}"
71
+ end
72
+
73
+ def self.reverse(str)
74
+ str.reverse
75
+ end
76
+ end
77
+
78
+ module MyReverser
79
+ def self.reverse(str)
80
+ str.reverse
81
+ end
82
+ end
83
+
84
+ def change_setting(klass, setting_name, value)
85
+ old_val = klass.class_variable_get(:"@@#{setting_name}")
86
+ klass.send("#{setting_name}=", value)
87
+ yield
88
+ ensure
89
+ klass.send("#{setting_name}=", old_val)
90
+ end
91
+
92
+ def run_job(job)
93
+ Delayed::Testing.run_job(job)
94
+ end
95
+
96
+ require File.expand_path('../sample_jobs', __FILE__)
97
+ require File.expand_path('../shared_jobs_specs', __FILE__)