que 0.11.3 → 2.2.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 (114) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/tests.yml +51 -0
  3. data/.gitignore +2 -0
  4. data/.ruby-version +1 -0
  5. data/CHANGELOG.md +502 -97
  6. data/Dockerfile +20 -0
  7. data/LICENSE.txt +1 -1
  8. data/README.md +205 -59
  9. data/auto/dev +21 -0
  10. data/auto/pre-push-hook +30 -0
  11. data/auto/psql +9 -0
  12. data/auto/test +5 -0
  13. data/auto/test-postgres-14 +17 -0
  14. data/bin/que +8 -81
  15. data/docker-compose.yml +47 -0
  16. data/docs/README.md +881 -0
  17. data/lib/que/active_job/extensions.rb +114 -0
  18. data/lib/que/active_record/connection.rb +51 -0
  19. data/lib/que/active_record/model.rb +48 -0
  20. data/lib/que/command_line_interface.rb +259 -0
  21. data/lib/que/connection.rb +198 -0
  22. data/lib/que/connection_pool.rb +78 -0
  23. data/lib/que/job.rb +210 -103
  24. data/lib/que/job_buffer.rb +255 -0
  25. data/lib/que/job_methods.rb +176 -0
  26. data/lib/que/listener.rb +176 -0
  27. data/lib/que/locker.rb +507 -0
  28. data/lib/que/metajob.rb +47 -0
  29. data/lib/que/migrations/4/down.sql +48 -0
  30. data/lib/que/migrations/4/up.sql +267 -0
  31. data/lib/que/migrations/5/down.sql +73 -0
  32. data/lib/que/migrations/5/up.sql +76 -0
  33. data/lib/que/migrations/6/down.sql +8 -0
  34. data/lib/que/migrations/6/up.sql +8 -0
  35. data/lib/que/migrations/7/down.sql +5 -0
  36. data/lib/que/migrations/7/up.sql +13 -0
  37. data/lib/que/migrations.rb +37 -18
  38. data/lib/que/poller.rb +274 -0
  39. data/lib/que/rails/railtie.rb +12 -0
  40. data/lib/que/result_queue.rb +35 -0
  41. data/lib/que/sequel/model.rb +52 -0
  42. data/lib/que/utils/assertions.rb +62 -0
  43. data/lib/que/utils/constantization.rb +19 -0
  44. data/lib/que/utils/error_notification.rb +68 -0
  45. data/lib/que/utils/freeze.rb +20 -0
  46. data/lib/que/utils/introspection.rb +50 -0
  47. data/lib/que/utils/json_serialization.rb +21 -0
  48. data/lib/que/utils/logging.rb +79 -0
  49. data/lib/que/utils/middleware.rb +46 -0
  50. data/lib/que/utils/queue_management.rb +18 -0
  51. data/lib/que/utils/ruby2_keywords.rb +19 -0
  52. data/lib/que/utils/transactions.rb +34 -0
  53. data/lib/que/version.rb +5 -1
  54. data/lib/que/worker.rb +145 -149
  55. data/lib/que.rb +103 -159
  56. data/que.gemspec +17 -4
  57. data/scripts/docker-entrypoint +14 -0
  58. data/scripts/test +6 -0
  59. metadata +59 -95
  60. data/.rspec +0 -2
  61. data/.travis.yml +0 -17
  62. data/Gemfile +0 -24
  63. data/docs/advanced_setup.md +0 -106
  64. data/docs/customizing_que.md +0 -200
  65. data/docs/error_handling.md +0 -47
  66. data/docs/inspecting_the_queue.md +0 -114
  67. data/docs/logging.md +0 -50
  68. data/docs/managing_workers.md +0 -80
  69. data/docs/migrating.md +0 -30
  70. data/docs/multiple_queues.md +0 -27
  71. data/docs/shutting_down_safely.md +0 -7
  72. data/docs/using_plain_connections.md +0 -41
  73. data/docs/using_sequel.md +0 -31
  74. data/docs/writing_reliable_jobs.md +0 -117
  75. data/lib/generators/que/install_generator.rb +0 -24
  76. data/lib/generators/que/templates/add_que.rb +0 -13
  77. data/lib/que/adapters/active_record.rb +0 -54
  78. data/lib/que/adapters/base.rb +0 -127
  79. data/lib/que/adapters/connection_pool.rb +0 -16
  80. data/lib/que/adapters/pg.rb +0 -21
  81. data/lib/que/adapters/pond.rb +0 -16
  82. data/lib/que/adapters/sequel.rb +0 -20
  83. data/lib/que/railtie.rb +0 -16
  84. data/lib/que/rake_tasks.rb +0 -59
  85. data/lib/que/sql.rb +0 -152
  86. data/spec/adapters/active_record_spec.rb +0 -152
  87. data/spec/adapters/connection_pool_spec.rb +0 -22
  88. data/spec/adapters/pg_spec.rb +0 -41
  89. data/spec/adapters/pond_spec.rb +0 -22
  90. data/spec/adapters/sequel_spec.rb +0 -57
  91. data/spec/gemfiles/Gemfile1 +0 -18
  92. data/spec/gemfiles/Gemfile2 +0 -18
  93. data/spec/spec_helper.rb +0 -118
  94. data/spec/support/helpers.rb +0 -19
  95. data/spec/support/jobs.rb +0 -35
  96. data/spec/support/shared_examples/adapter.rb +0 -37
  97. data/spec/support/shared_examples/multi_threaded_adapter.rb +0 -46
  98. data/spec/travis.rb +0 -23
  99. data/spec/unit/connection_spec.rb +0 -14
  100. data/spec/unit/customization_spec.rb +0 -251
  101. data/spec/unit/enqueue_spec.rb +0 -245
  102. data/spec/unit/helper_spec.rb +0 -12
  103. data/spec/unit/logging_spec.rb +0 -101
  104. data/spec/unit/migrations_spec.rb +0 -84
  105. data/spec/unit/pool_spec.rb +0 -365
  106. data/spec/unit/run_spec.rb +0 -14
  107. data/spec/unit/states_spec.rb +0 -50
  108. data/spec/unit/stats_spec.rb +0 -46
  109. data/spec/unit/transaction_spec.rb +0 -36
  110. data/spec/unit/work_spec.rb +0 -407
  111. data/spec/unit/worker_spec.rb +0 -167
  112. data/tasks/benchmark.rb +0 -3
  113. data/tasks/rspec.rb +0 -14
  114. data/tasks/safe_shutdown.rb +0 -67
@@ -1,407 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe Que::Job, '.work' do
6
- it "should pass a job's arguments to the run method and delete it from the database" do
7
- ArgsJob.enqueue 1, 'two', {'three' => 3}
8
- DB[:que_jobs].count.should be 1
9
-
10
- result = Que::Job.work
11
- result[:event].should == :job_worked
12
- result[:job][:job_class].should == 'ArgsJob'
13
-
14
- DB[:que_jobs].count.should be 0
15
- $passed_args.should == [1, 'two', {'three' => 3}]
16
- end
17
-
18
- it "should respect a custom json converter when processing the job's arguments" do
19
- ArgsJob.enqueue 1, 'two', {'three' => 3}
20
- DB[:que_jobs].count.should be 1
21
-
22
- begin
23
- Que.json_converter = Que::SYMBOLIZER
24
-
25
- result = Que::Job.work
26
- result[:event].should == :job_worked
27
- result[:job][:job_class].should == 'ArgsJob'
28
-
29
- DB[:que_jobs].count.should be 0
30
- $passed_args.should == [1, 'two', {:three => 3}]
31
- ensure
32
- Que.json_converter = Que::INDIFFERENTIATOR
33
- end
34
- end
35
-
36
- it "should default to only working jobs without a named queue" do
37
- Que::Job.enqueue 1, :queue => 'other_queue'
38
- Que::Job.enqueue 2
39
-
40
- result = Que::Job.work
41
- result[:event].should == :job_worked
42
- result[:job][:args].should == [2]
43
-
44
- result = Que::Job.work
45
- result[:event].should == :job_unavailable
46
- end
47
-
48
- it "should accept the name of a single queue to pull jobs from" do
49
- Que::Job.enqueue 1, :queue => 'other_queue'
50
- Que::Job.enqueue 2, :queue => 'other_queue'
51
- Que::Job.enqueue 3
52
-
53
- result = Que::Job.work(:other_queue)
54
- result[:event].should == :job_worked
55
- result[:job][:args].should == [1]
56
-
57
- result = Que::Job.work('other_queue')
58
- result[:event].should == :job_worked
59
- result[:job][:args].should == [2]
60
-
61
- result = Que::Job.work(:other_queue)
62
- result[:event].should == :job_unavailable
63
- end
64
-
65
- it "should make a job's argument hashes indifferently accessible" do
66
- DB[:que_jobs].count.should be 0
67
- ArgsJob.enqueue 1, 'two', {'array' => [{'number' => 3}]}
68
- DB[:que_jobs].count.should be 1
69
-
70
- result = Que::Job.work
71
- result[:event].should == :job_worked
72
- result[:job][:job_class].should == 'ArgsJob'
73
-
74
- DB[:que_jobs].count.should be 0
75
-
76
- $passed_args.last[:array].first[:number].should == 3
77
- end
78
-
79
- it "should not fail if there are no jobs to work" do
80
- Que::Job.work[:event].should be :job_unavailable
81
- end
82
-
83
- it "should prefer a job with a higher priority" do
84
- # 1 is highest priority.
85
- [5, 4, 3, 2, 1, 2, 3, 4, 5].map{|p| Que::Job.enqueue :priority => p}
86
- DB[:que_jobs].order(:job_id).select_map(:priority).should == [5, 4, 3, 2, 1, 2, 3, 4, 5]
87
-
88
- result = Que::Job.work
89
- result[:event].should == :job_worked
90
- result[:job][:job_class].should == 'Que::Job'
91
- DB[:que_jobs].select_map(:priority).should == [5, 4, 3, 2, 2, 3, 4, 5]
92
- end
93
-
94
- it "should prefer a job that was scheduled to run longer ago when priorities are equal" do
95
- Que::Job.enqueue :run_at => Time.now - 30
96
- Que::Job.enqueue :run_at => Time.now - 60
97
- Que::Job.enqueue :run_at => Time.now - 30
98
-
99
- recent1, old, recent2 = DB[:que_jobs].order(:job_id).select_map(:run_at)
100
-
101
- result = Que::Job.work
102
- result[:event].should == :job_worked
103
- result[:job][:job_class].should == 'Que::Job'
104
- DB[:que_jobs].order_by(:job_id).select_map(:run_at).should == [recent1, recent2]
105
- end
106
-
107
- it "should prefer a job that was queued earlier when priorities and run_ats are equal" do
108
- run_at = Time.now - 30
109
- Que::Job.enqueue :run_at => run_at
110
- Que::Job.enqueue :run_at => run_at
111
- Que::Job.enqueue :run_at => run_at
112
-
113
- first, second, third = DB[:que_jobs].select_order_map(:job_id)
114
-
115
- result = Que::Job.work
116
- result[:event].should == :job_worked
117
- result[:job][:job_class].should == 'Que::Job'
118
- DB[:que_jobs].select_order_map(:job_id).should == [second, third]
119
- end
120
-
121
- it "should only work a job whose scheduled time to run has passed" do
122
- Que::Job.enqueue :run_at => Time.now + 30
123
- Que::Job.enqueue :run_at => Time.now - 30
124
- Que::Job.enqueue :run_at => Time.now + 30
125
-
126
- future1, past, future2 = DB[:que_jobs].order(:job_id).select_map(:run_at)
127
-
128
- result = Que::Job.work
129
- result[:event].should == :job_worked
130
- result[:job][:job_class].should == 'Que::Job'
131
- Que::Job.work[:event].should be :job_unavailable
132
- DB[:que_jobs].order_by(:job_id).select_map(:run_at).should == [future1, future2]
133
- end
134
-
135
- it "should lock the job it selects" do
136
- BlockJob.enqueue
137
- id = DB[:que_jobs].get(:job_id)
138
- thread = Thread.new { Que::Job.work }
139
-
140
- $q1.pop
141
- DB[:pg_locks].where(:locktype => 'advisory').select_map(:objid).should == [id]
142
- $q2.push nil
143
-
144
- thread.join
145
- end
146
-
147
- it "should skip jobs that are advisory-locked" do
148
- Que::Job.enqueue :priority => 2
149
- Que::Job.enqueue :priority => 1
150
- Que::Job.enqueue :priority => 3
151
- id = DB[:que_jobs].where(:priority => 1).get(:job_id)
152
-
153
- begin
154
- DB.select{pg_advisory_lock(id)}.single_value
155
-
156
- result = Que::Job.work
157
- result[:event].should == :job_worked
158
- result[:job][:job_class].should == 'Que::Job'
159
-
160
- DB[:que_jobs].order_by(:job_id).select_map(:priority).should == [1, 3]
161
- ensure
162
- DB.select{pg_advisory_unlock(id)}.single_value
163
- end
164
- end
165
-
166
- it "should handle subclasses of other jobs" do
167
- class SubClassJob < Que::Job
168
- @priority = 2
169
-
170
- def run
171
- $job_spec_result << :sub
172
- end
173
- end
174
-
175
- class SubSubClassJob < SubClassJob
176
- @priority = 4
177
-
178
- def run
179
- super
180
- $job_spec_result << :subsub
181
- end
182
- end
183
-
184
- $job_spec_result = []
185
- SubClassJob.enqueue
186
- DB[:que_jobs].select_map(:priority).should == [2]
187
- result = Que::Job.work
188
- result[:event].should == :job_worked
189
- result[:job][:job_class].should == 'SubClassJob'
190
- $job_spec_result.should == [:sub]
191
-
192
- $job_spec_result = []
193
- SubSubClassJob.enqueue
194
- DB[:que_jobs].select_map(:priority).should == [4]
195
- result = Que::Job.work
196
- result[:event].should == :job_worked
197
- result[:job][:job_class].should == 'SubSubClassJob'
198
- $job_spec_result.should == [:sub, :subsub]
199
- end
200
-
201
- it "should handle namespaced subclasses" do
202
- module ModuleJobModule
203
- class ModuleJob < Que::Job
204
- end
205
- end
206
-
207
- ModuleJobModule::ModuleJob.enqueue
208
- DB[:que_jobs].get(:job_class).should == "ModuleJobModule::ModuleJob"
209
-
210
- result = Que::Job.work
211
- result[:event].should == :job_worked
212
- result[:job][:job_class].should == 'ModuleJobModule::ModuleJob'
213
- end
214
-
215
- it "should make it easy to destroy the job within the same transaction as other changes" do
216
- class DestroyJob < Que::Job
217
- def run
218
- destroy
219
- end
220
- end
221
-
222
- DestroyJob.enqueue
223
- DB[:que_jobs].count.should be 1
224
- Que::Job.work
225
- DB[:que_jobs].count.should be 0
226
- end
227
-
228
- describe "when encountering an error" do
229
- it "should exponentially back off the job" do
230
- ErrorJob.enqueue
231
-
232
- result = Que::Job.work
233
- result[:event].should == :job_errored
234
- result[:error].should be_an_instance_of RuntimeError
235
- result[:job][:job_class].should == 'ErrorJob'
236
-
237
- DB[:que_jobs].count.should be 1
238
- job = DB[:que_jobs].first
239
- job[:error_count].should be 1
240
- job[:last_error].should =~ /\AErrorJob!\n/
241
- job[:run_at].should be_within(3).of Time.now + 4
242
-
243
- DB[:que_jobs].update :error_count => 5,
244
- :run_at => Time.now - 60
245
-
246
- result = Que::Job.work
247
- result[:event].should == :job_errored
248
- result[:error].should be_an_instance_of RuntimeError
249
- result[:job][:job_class].should == 'ErrorJob'
250
-
251
- DB[:que_jobs].count.should be 1
252
- job = DB[:que_jobs].first
253
- job[:error_count].should be 6
254
- job[:last_error].should =~ /\AErrorJob!\n/
255
- job[:run_at].should be_within(3).of Time.now + 1299
256
- end
257
-
258
- it "should respect a custom retry interval" do
259
- class RetryIntervalJob < ErrorJob
260
- @retry_interval = 3155760000000 # 100,000 years from now
261
- end
262
-
263
- RetryIntervalJob.enqueue
264
-
265
- result = Que::Job.work
266
- result[:event].should == :job_errored
267
- result[:error].should be_an_instance_of RuntimeError
268
- result[:job][:job_class].should == 'RetryIntervalJob'
269
-
270
- DB[:que_jobs].count.should be 1
271
- job = DB[:que_jobs].first
272
- job[:error_count].should be 1
273
- job[:last_error].should =~ /\AErrorJob!\n/
274
- job[:run_at].to_f.should be_within(3).of Time.now.to_f + RetryIntervalJob.retry_interval
275
-
276
- DB[:que_jobs].update :error_count => 5,
277
- :run_at => Time.now - 60
278
-
279
- result = Que::Job.work
280
- result[:event].should == :job_errored
281
- result[:error].should be_an_instance_of RuntimeError
282
- result[:job][:job_class].should == 'RetryIntervalJob'
283
-
284
- DB[:que_jobs].count.should be 1
285
- job = DB[:que_jobs].first
286
- job[:error_count].should be 6
287
- job[:last_error].should =~ /\AErrorJob!\n/
288
- job[:run_at].to_f.should be_within(3).of Time.now.to_f + RetryIntervalJob.retry_interval
289
- end
290
-
291
- it "should respect a custom retry interval formula" do
292
- class RetryIntervalFormulaJob < ErrorJob
293
- @retry_interval = proc { |count| count * 10 }
294
- end
295
-
296
- RetryIntervalFormulaJob.enqueue
297
-
298
- result = Que::Job.work
299
- result[:event].should == :job_errored
300
- result[:error].should be_an_instance_of RuntimeError
301
- result[:job][:job_class].should == 'RetryIntervalFormulaJob'
302
-
303
- DB[:que_jobs].count.should be 1
304
- job = DB[:que_jobs].first
305
- job[:error_count].should be 1
306
- job[:last_error].should =~ /\AErrorJob!\n/
307
- job[:run_at].should be_within(3).of Time.now + 10
308
-
309
- DB[:que_jobs].update :error_count => 5,
310
- :run_at => Time.now - 60
311
-
312
- result = Que::Job.work
313
- result[:event].should == :job_errored
314
- result[:error].should be_an_instance_of RuntimeError
315
- result[:job][:job_class].should == 'RetryIntervalFormulaJob'
316
-
317
- DB[:que_jobs].count.should be 1
318
- job = DB[:que_jobs].first
319
- job[:error_count].should be 6
320
- job[:last_error].should =~ /\AErrorJob!\n/
321
- job[:run_at].should be_within(3).of Time.now + 60
322
- end
323
-
324
- it "should pass it to an error handler, if one is defined" do
325
- begin
326
- errors = []
327
- Que.error_handler = proc { |error| errors << error }
328
-
329
- ErrorJob.enqueue
330
-
331
- result = Que::Job.work
332
- result[:event].should == :job_errored
333
- result[:error].should be_an_instance_of RuntimeError
334
- result[:job][:job_class].should == 'ErrorJob'
335
-
336
- errors.count.should be 1
337
- error = errors[0]
338
- error.should be_an_instance_of RuntimeError
339
- error.message.should == "ErrorJob!"
340
- ensure
341
- Que.error_handler = nil
342
- end
343
- end
344
-
345
- it "should pass job to an error handler, if one is defined" do
346
- begin
347
- jobs = []
348
- Que.error_handler = proc { |error, job| jobs << job }
349
-
350
- ErrorJob.enqueue
351
- result = Que::Job.work
352
-
353
- jobs.count.should be 1
354
- job = jobs[0]
355
- job.should be result[:job]
356
- ensure
357
- Que.error_handler = nil
358
- end
359
- end
360
-
361
- it "should not do anything if the error handler itelf throws an error" do
362
- begin
363
- Que.error_handler = proc { |error| raise "Another error!" }
364
- ErrorJob.enqueue
365
-
366
- result = Que::Job.work
367
- result[:event].should == :job_errored
368
- result[:error].should be_an_instance_of RuntimeError
369
- ensure
370
- Que.error_handler = nil
371
- end
372
- end
373
-
374
- it "should throw an error properly if there's no corresponding job class" do
375
- DB[:que_jobs].insert :job_class => "NonexistentClass"
376
-
377
- result = Que::Job.work
378
- result[:event].should == :job_errored
379
- result[:error].should be_an_instance_of NameError
380
- result[:job][:job_class].should == 'NonexistentClass'
381
-
382
- DB[:que_jobs].count.should be 1
383
- job = DB[:que_jobs].first
384
- job[:error_count].should be 1
385
- job[:last_error].should =~ /uninitialized constant:? NonexistentClass/
386
- job[:run_at].should be_within(3).of Time.now + 4
387
- end
388
-
389
- it "should throw an error properly if the corresponding job class doesn't descend from Que::Job" do
390
- class J
391
- def run(*args)
392
- end
393
- end
394
-
395
- Que.enqueue :job_class => "J"
396
-
397
- result = Que::Job.work
398
- result[:event].should == :job_errored
399
- result[:job][:job_class].should == 'J'
400
-
401
- DB[:que_jobs].count.should be 1
402
- job = DB[:que_jobs].first
403
- job[:error_count].should be 1
404
- job[:run_at].should be_within(3).of Time.now + 4
405
- end
406
- end
407
- end
@@ -1,167 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe Que::Worker do
6
- it "should work jobs when started until there are none available" do
7
- begin
8
- Que::Job.enqueue
9
- Que::Job.enqueue
10
- DB[:que_jobs].count.should be 2
11
-
12
- @worker = Que::Worker.new
13
- sleep_until { @worker.sleeping? }
14
- DB[:que_jobs].count.should be 0
15
-
16
- $logger.messages.map{|m| JSON.load(m)['event']}.should == %w(job_worked job_worked job_unavailable)
17
-
18
- json = JSON.load($logger.messages[0])
19
- json['job']['job_class'].should == 'Que::Job'
20
- ensure
21
- if @worker
22
- @worker.stop
23
- @worker.wait_until_stopped
24
- end
25
- end
26
- end
27
-
28
- it "should work jobs without a named queue by default" do
29
- begin
30
- Que::Job.enqueue 1
31
- Que::Job.enqueue 2, :queue => 'my_queue'
32
-
33
- @worker = Que::Worker.new
34
- sleep_until { @worker.sleeping? }
35
- DB[:que_jobs].count.should be 1
36
-
37
- $logger.messages.map{|m| JSON.load(m)['event']}.should == %w(job_worked job_unavailable)
38
-
39
- json = JSON.load($logger.messages[0])
40
- json['job']['queue'].should == ''
41
- json['job']['job_class'].should == 'Que::Job'
42
- json['job']['args'].should == [1]
43
- ensure
44
- if @worker
45
- @worker.stop
46
- @worker.wait_until_stopped
47
- end
48
- end
49
- end
50
-
51
- it "should accept the name of a single queue to work jobs from" do
52
- begin
53
- Que::Job.enqueue 1
54
- Que::Job.enqueue 2, :queue => 'my_queue'
55
-
56
- @worker = Que::Worker.new(:my_queue)
57
- sleep_until { @worker.sleeping? }
58
- DB[:que_jobs].count.should be 1
59
-
60
- $logger.messages.map{|m| JSON.load(m)['event']}.should == %w(job_worked job_unavailable)
61
-
62
- json = JSON.load($logger.messages[0])
63
- json['job']['queue'].should == 'my_queue'
64
- json['job']['job_class'].should == 'Que::Job'
65
- json['job']['args'].should == [2]
66
- ensure
67
- if @worker
68
- @worker.stop
69
- @worker.wait_until_stopped
70
- end
71
- end
72
- end
73
-
74
- it "#wake! should return truthy if the worker was asleep and is woken up, at which point it should work until no jobs are available" do
75
- begin
76
- @worker = Que::Worker.new
77
- sleep_until { @worker.sleeping? }
78
-
79
- Que::Job.enqueue
80
- Que::Job.enqueue
81
- DB[:que_jobs].count.should be 2
82
-
83
- @worker.wake!.should be true
84
- sleep_until { @worker.sleeping? }
85
- DB[:que_jobs].count.should be 0
86
- ensure
87
- if @worker
88
- @worker.stop
89
- @worker.wait_until_stopped
90
- end
91
- end
92
- end
93
-
94
- it "#wake! should return falsy if the worker was already working" do
95
- begin
96
- BlockJob.enqueue
97
- @worker = Que::Worker.new
98
-
99
- $q1.pop
100
- DB[:que_jobs].count.should be 1
101
- @worker.wake!.should be nil
102
- $q2.push nil
103
- ensure
104
- if @worker
105
- @worker.stop
106
- @worker.wait_until_stopped
107
- end
108
- end
109
- end
110
-
111
- it "should not be deterred by a job that raises an error" do
112
- begin
113
- ErrorJob.enqueue :priority => 1
114
- Que::Job.enqueue :priority => 5
115
-
116
- @worker = Que::Worker.new
117
-
118
- sleep_until { @worker.sleeping? }
119
-
120
- DB[:que_jobs].count.should be 1
121
- job = DB[:que_jobs].first
122
- job[:job_class].should == 'ErrorJob'
123
- job[:run_at].should be_within(3).of Time.now + 4
124
-
125
- log = JSON.load($logger.messages[0])
126
- log['event'].should == 'job_errored'
127
- log['error']['class'].should == 'RuntimeError'
128
- log['error']['message'].should == "ErrorJob!"
129
- log['job']['job_class'].should == 'ErrorJob'
130
- ensure
131
- if @worker
132
- @worker.stop
133
- @worker.wait_until_stopped
134
- end
135
- end
136
- end
137
-
138
- it "should receive and respect a notification to stop down when it is working, after its current job completes" do
139
- begin
140
- BlockJob.enqueue :priority => 1
141
- Que::Job.enqueue :priority => 5
142
- DB[:que_jobs].count.should be 2
143
-
144
- @worker = Que::Worker.new
145
-
146
- $q1.pop
147
- @worker.stop
148
- $q2.push nil
149
-
150
- @worker.wait_until_stopped
151
-
152
- DB[:que_jobs].count.should be 1
153
- job = DB[:que_jobs].first
154
- job[:job_class].should == 'Que::Job'
155
- end
156
- end
157
-
158
- it "should receive and respect a notification to stop when it is currently asleep" do
159
- begin
160
- @worker = Que::Worker.new
161
- sleep_until { @worker.sleeping? }
162
-
163
- @worker.stop
164
- @worker.wait_until_stopped
165
- end
166
- end
167
- end
data/tasks/benchmark.rb DELETED
@@ -1,3 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # The benchmarking tasks have been merged together and now live at github.com/chanks/queue-shootout.
data/tasks/rspec.rb DELETED
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rspec/core/rake_task'
4
-
5
- RSpec::Core::RakeTask.new :default do |spec|
6
- spec.pattern = './spec/**/*_spec.rb'
7
- end
8
-
9
- # Shortcut to skip the adapter specs, and run only with the basic PG
10
- # connection. I use this occasionally to make sure ActiveRecord isn't loaded,
11
- # so any accidental Rails-isms are caught.
12
- RSpec::Core::RakeTask.new :pg do |spec|
13
- spec.pattern = './spec/unit/*_spec.rb'
14
- end
@@ -1,67 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # This task is used to test Que's behavior when its process is shut down.
4
-
5
- # The situation we're trying to avoid occurs when the process dies while a job
6
- # is in the middle of a transaction - ideally, the transaction would be rolled
7
- # back and the job could just be reattempted later, but if we're not careful,
8
- # the transaction could be committed prematurely. For specifics, see here:
9
-
10
- # http://coderrr.wordpress.com/2011/05/03/beware-of-threadkill-or-your-activerecord-transactions-are-in-danger-of-being-partially-committed/
11
-
12
- # So, this task opens a transaction within a job, makes a write, then prompts
13
- # you to kill it with one of a few signals. You can then run it again to make
14
- # sure that the write was rolled back (if it wasn't, Que isn't functioning
15
- # like it should). This task only explicitly tests Sequel, but the behavior
16
- # for ActiveRecord is very similar.
17
-
18
- task :safe_shutdown do
19
- require 'sequel'
20
- require 'que'
21
-
22
- url = ENV['DATABASE_URL'] || 'postgres://postgres:@localhost/que-test'
23
- DB = Sequel.connect(url)
24
-
25
- if DB.table_exists?(:que_jobs)
26
- puts "Uh-oh! Previous shutdown wasn't clean!" if DB[:que_jobs].where(:job_id => 0).count > 0
27
- DB.drop_table :que_jobs
28
- end
29
-
30
- Que.connection = DB
31
- Que.create!
32
-
33
- $queue = Queue.new
34
-
35
- class SafeJob < Que::Job
36
- def run
37
- DB.transaction do
38
- DB[:que_jobs].insert(:job_id => 0, :job_class => 'Que::Job')
39
- $queue.push nil
40
- sleep
41
- end
42
- end
43
- end
44
-
45
- SafeJob.enqueue
46
- Que.mode = :async
47
- $queue.pop
48
-
49
- puts "From a different terminal window, run one of the following:"
50
- %w(SIGINT SIGTERM SIGKILL).each do |signal|
51
- puts "kill -#{signal} #{Process.pid}"
52
- end
53
-
54
- stop = false
55
- trap('INT'){stop = true}
56
-
57
- at_exit do
58
- $stdout.puts "Finishing Que's current jobs before exiting..."
59
- Que.mode = :off
60
- $stdout.puts "Que's jobs finished, exiting..."
61
- end
62
-
63
- loop do
64
- sleep 0.01
65
- break if stop
66
- end
67
- end