que 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/.travis.yml +1 -1
- data/CHANGELOG.md +21 -1
- data/Gemfile +5 -0
- data/README.md +7 -6
- data/docs/advanced_setup.md +14 -4
- data/docs/customizing_que.md +4 -4
- data/docs/error_handling.md +13 -1
- data/docs/managing_workers.md +2 -2
- data/docs/migrating.md +26 -0
- data/docs/multiple_queues.md +13 -0
- data/docs/shutting_down_safely.md +7 -0
- data/docs/writing_reliable_jobs.md +43 -0
- data/lib/generators/que/templates/add_que.rb +1 -1
- data/lib/que.rb +27 -41
- data/lib/que/adapters/base.rb +75 -4
- data/lib/que/job.rb +45 -28
- data/lib/que/migrations.rb +3 -2
- data/lib/que/migrations/{1-down.sql → 1/down.sql} +0 -0
- data/lib/que/migrations/{1-up.sql → 1/up.sql} +0 -0
- data/lib/que/migrations/{2-down.sql → 2/down.sql} +0 -0
- data/lib/que/migrations/{2-up.sql → 2/up.sql} +0 -0
- data/lib/que/migrations/3/down.sql +5 -0
- data/lib/que/migrations/3/up.sql +5 -0
- data/lib/que/sql.rb +24 -17
- data/lib/que/version.rb +1 -1
- data/lib/que/worker.rb +6 -5
- data/spec/adapters/active_record_spec.rb +6 -6
- data/spec/adapters/sequel_spec.rb +4 -4
- data/spec/gemfiles/Gemfile1 +18 -0
- data/spec/gemfiles/Gemfile2 +18 -0
- data/spec/support/helpers.rb +2 -1
- data/spec/support/shared_examples/adapter.rb +7 -3
- data/spec/support/shared_examples/multi_threaded_adapter.rb +2 -2
- data/spec/travis.rb +12 -4
- data/spec/unit/customization_spec.rb +148 -0
- data/spec/unit/{queue_spec.rb → enqueue_spec.rb} +115 -14
- data/spec/unit/logging_spec.rb +3 -2
- data/spec/unit/migrations_spec.rb +3 -2
- data/spec/unit/pool_spec.rb +30 -6
- data/spec/unit/run_spec.rb +12 -0
- data/spec/unit/states_spec.rb +29 -31
- data/spec/unit/stats_spec.rb +16 -14
- data/spec/unit/work_spec.rb +120 -25
- data/spec/unit/worker_spec.rb +55 -9
- data/tasks/safe_shutdown.rb +1 -1
- metadata +30 -17
data/spec/unit/logging_spec.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe "Logging" do
|
4
|
-
it "by default should record the library and thread id in JSON" do
|
4
|
+
it "by default should record the library and hostname and thread id in JSON" do
|
5
5
|
Que.log :event => "blah", :source => 4
|
6
6
|
$logger.messages.count.should be 1
|
7
7
|
|
8
8
|
message = JSON.load($logger.messages.first)
|
9
9
|
message['lib'].should == 'que'
|
10
|
+
message['hostname'].should == Socket.gethostname
|
10
11
|
message['event'].should == 'blah'
|
11
12
|
message['source'].should == 4
|
12
13
|
message['thread'].should == Thread.current.object_id
|
@@ -16,7 +17,7 @@ describe "Logging" do
|
|
16
17
|
begin
|
17
18
|
Que.logger = nil
|
18
19
|
|
19
|
-
Que::Job.
|
20
|
+
Que::Job.enqueue
|
20
21
|
worker = Que::Worker.new
|
21
22
|
sleep_until { worker.sleeping? }
|
22
23
|
|
@@ -7,7 +7,7 @@ describe Que::Migrations do
|
|
7
7
|
|
8
8
|
default = proc do
|
9
9
|
result = Que.execute <<-SQL
|
10
|
-
select adsrc
|
10
|
+
select adsrc::integer
|
11
11
|
from pg_attribute a
|
12
12
|
join pg_class c on c.oid = a.attrelid
|
13
13
|
join pg_attrdef on adrelid = attrelid AND adnum = attnum
|
@@ -15,7 +15,7 @@ describe Que::Migrations do
|
|
15
15
|
and attname = 'priority'
|
16
16
|
SQL
|
17
17
|
|
18
|
-
result.first[
|
18
|
+
result.first[:adsrc]
|
19
19
|
end
|
20
20
|
|
21
21
|
default.call.should == 100
|
@@ -40,6 +40,7 @@ describe Que::Migrations do
|
|
40
40
|
Que::Migrations.db_version.should == Que::Migrations::CURRENT_VERSION
|
41
41
|
Que::Migrations.migrate! :version => 0
|
42
42
|
Que::Migrations.db_version.should == 0
|
43
|
+
Que.db_version.should == 0
|
43
44
|
Que::Migrations.migrate!
|
44
45
|
Que::Migrations.db_version.should == Que::Migrations::CURRENT_VERSION
|
45
46
|
|
data/spec/unit/pool_spec.rb
CHANGED
@@ -19,15 +19,15 @@ describe "Managing the Worker pool" do
|
|
19
19
|
it "should make jobs run in the same thread as they are queued" do
|
20
20
|
Que.mode = :sync
|
21
21
|
|
22
|
-
ArgsJob.
|
23
|
-
$passed_args.should == [5, {
|
22
|
+
ArgsJob.enqueue(5, :testing => "synchronous").should be_an_instance_of ArgsJob
|
23
|
+
$passed_args.should == [5, {:testing => "synchronous"}]
|
24
24
|
DB[:que_jobs].count.should be 0
|
25
25
|
end
|
26
26
|
|
27
27
|
it "should not affect jobs that are queued with specific run_ats" do
|
28
28
|
Que.mode = :sync
|
29
29
|
|
30
|
-
ArgsJob.
|
30
|
+
ArgsJob.enqueue(5, :testing => "synchronous", :run_at => Time.now + 60)
|
31
31
|
DB[:que_jobs].select_map(:job_class).should == ["ArgsJob"]
|
32
32
|
end
|
33
33
|
end
|
@@ -132,7 +132,7 @@ describe "Managing the Worker pool" do
|
|
132
132
|
Que.mode = :async
|
133
133
|
sleep_until { Que::Worker.workers.all? &:sleeping? }
|
134
134
|
|
135
|
-
BlockJob.
|
135
|
+
BlockJob.enqueue
|
136
136
|
Que.wake!
|
137
137
|
|
138
138
|
$q1.pop
|
@@ -158,7 +158,7 @@ describe "Managing the Worker pool" do
|
|
158
158
|
Que.mode = :async
|
159
159
|
sleep_until { Que::Worker.workers.all? &:sleeping? }
|
160
160
|
|
161
|
-
4.times { BlockJob.
|
161
|
+
4.times { BlockJob.enqueue }
|
162
162
|
Que.wake_all!
|
163
163
|
4.times { $q1.pop }
|
164
164
|
|
@@ -179,8 +179,32 @@ describe "Managing the Worker pool" do
|
|
179
179
|
Que.mode = :async
|
180
180
|
sleep_until { Que::Worker.workers.all? &:sleeping? }
|
181
181
|
Que.wake_interval = 0.01 # 10 ms
|
182
|
-
Que::Job.
|
182
|
+
Que::Job.enqueue
|
183
183
|
sleep_until { DB[:que_jobs].count == 0 }
|
184
184
|
end
|
185
|
+
|
186
|
+
it "should work jobs in the queue defined by QUE_QUEUE" do
|
187
|
+
begin
|
188
|
+
Que::Job.enqueue 1
|
189
|
+
Que::Job.enqueue 2, :queue => 'my_queue'
|
190
|
+
|
191
|
+
ENV['QUE_QUEUE'] = 'my_queue'
|
192
|
+
|
193
|
+
Que.mode = :async
|
194
|
+
sleep_until { Que::Worker.workers.all? &:sleeping? }
|
195
|
+
DB[:que_jobs].count.should be 1
|
196
|
+
|
197
|
+
job = DB[:que_jobs].first
|
198
|
+
job[:queue].should == ''
|
199
|
+
job[:args].should == '[1]'
|
200
|
+
ensure
|
201
|
+
ENV.delete('QUE_QUEUE')
|
202
|
+
|
203
|
+
if @worker
|
204
|
+
@worker.stop
|
205
|
+
@worker.wait_until_stopped
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
185
209
|
end
|
186
210
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Que::Job, '.run' do
|
4
|
+
it "should immediately process the job with the arguments given to it" do
|
5
|
+
result = ArgsJob.run 1, 'two', {:three => 3}
|
6
|
+
result.should be_an_instance_of ArgsJob
|
7
|
+
result.attrs[:args].should == [1, 'two', {:three => 3}]
|
8
|
+
|
9
|
+
DB[:que_jobs].count.should be 0
|
10
|
+
$passed_args.should == [1, 'two', {:three => 3}]
|
11
|
+
end
|
12
|
+
end
|
data/spec/unit/states_spec.rb
CHANGED
@@ -6,45 +6,43 @@ describe Que, '.worker_states' do
|
|
6
6
|
|
7
7
|
class WorkerStateJob < BlockJob
|
8
8
|
def run
|
9
|
-
$pid = Que.execute("select pg_backend_pid()").first[
|
9
|
+
$pid = Que.execute("select pg_backend_pid()").first[:pg_backend_pid]
|
10
10
|
super
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
WorkerStateJob.
|
14
|
+
WorkerStateJob.enqueue :priority => 2
|
15
15
|
|
16
16
|
# Ensure that the portion of the SQL query that accounts for bigint
|
17
17
|
# job_ids functions correctly.
|
18
18
|
DB[:que_jobs].update(:job_id => 2**33)
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
state[:pg_waiting_on_lock].should == 'f'
|
48
|
-
end
|
20
|
+
t = Thread.new { Que::Job.work }
|
21
|
+
$q1.pop
|
22
|
+
|
23
|
+
states = Que.worker_states
|
24
|
+
states.length.should be 1
|
25
|
+
|
26
|
+
$q2.push nil
|
27
|
+
t.join
|
28
|
+
|
29
|
+
state = states.first
|
30
|
+
state.keys.should == %w(priority run_at job_id job_class args error_count last_error queue pg_backend_pid pg_state pg_state_changed_at pg_last_query pg_last_query_started_at pg_transaction_started_at pg_waiting_on_lock)
|
31
|
+
|
32
|
+
state[:priority].should == 2
|
33
|
+
state[:run_at].should be_within(3).of Time.now
|
34
|
+
state[:job_id].should == 2**33
|
35
|
+
state[:job_class].should == 'WorkerStateJob'
|
36
|
+
state[:args].should == []
|
37
|
+
state[:error_count].should == 0
|
38
|
+
state[:last_error].should be nil
|
39
|
+
|
40
|
+
state[:pg_backend_pid].should == $pid
|
41
|
+
state[:pg_state].should == 'idle'
|
42
|
+
state[:pg_state_changed_at].should be_within(3).of Time.now
|
43
|
+
state[:pg_last_query].should == 'select pg_backend_pid()'
|
44
|
+
state[:pg_last_query_started_at].should be_within(3).of Time.now
|
45
|
+
state[:pg_transaction_started_at].should == nil
|
46
|
+
state[:pg_waiting_on_lock].should == false
|
49
47
|
end if QUE_ADAPTERS[:connection_pool]
|
50
48
|
end
|
data/spec/unit/stats_spec.rb
CHANGED
@@ -2,15 +2,15 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Que, '.job_stats' do
|
4
4
|
it "should return a list of the job types in the queue, their counts and the number of each currently running" do
|
5
|
-
BlockJob.
|
6
|
-
Que::Job.
|
5
|
+
BlockJob.enqueue
|
6
|
+
Que::Job.enqueue
|
7
7
|
|
8
8
|
# Have to tweak the job_id to ensure that the portion of the SQL query
|
9
9
|
# that accounts for bigint job_ids functions correctly.
|
10
10
|
old = Time.now - 3600
|
11
11
|
DB[:que_jobs].where(:job_class => "Que::Job").update(:job_id => 2**33, :error_count => 5, :run_at => old)
|
12
12
|
|
13
|
-
Que::Job.
|
13
|
+
Que::Job.enqueue
|
14
14
|
|
15
15
|
begin
|
16
16
|
DB.get{pg_advisory_lock(2**33)}
|
@@ -20,21 +20,23 @@ describe Que, '.job_stats' do
|
|
20
20
|
|
21
21
|
qj, bj = stats
|
22
22
|
|
23
|
-
qj.keys.should == %w(job_class count count_working count_errored highest_error_count oldest_run_at)
|
23
|
+
qj.keys.should == %w(queue job_class count count_working count_errored highest_error_count oldest_run_at)
|
24
24
|
|
25
|
+
qj[:queue].should == ''
|
25
26
|
qj[:job_class].should == 'Que::Job'
|
26
|
-
qj[:count].should ==
|
27
|
-
qj[:count_working].should ==
|
28
|
-
qj[:count_errored].should ==
|
29
|
-
qj[:highest_error_count].should ==
|
30
|
-
|
27
|
+
qj[:count].should == 2
|
28
|
+
qj[:count_working].should == 1
|
29
|
+
qj[:count_errored].should == 1
|
30
|
+
qj[:highest_error_count].should == 5
|
31
|
+
qj[:oldest_run_at].should be_within(3).of old
|
31
32
|
|
33
|
+
bj[:queue].should == ''
|
32
34
|
bj[:job_class].should == 'BlockJob'
|
33
|
-
bj[:count].should ==
|
34
|
-
bj[:count_working].should ==
|
35
|
-
bj[:count_errored].should ==
|
36
|
-
bj[:highest_error_count].should ==
|
37
|
-
|
35
|
+
bj[:count].should == 1
|
36
|
+
bj[:count_working].should == 0
|
37
|
+
bj[:count_errored].should == 0
|
38
|
+
bj[:highest_error_count].should == 0
|
39
|
+
bj[:oldest_run_at].should be_within(3).of Time.now
|
38
40
|
ensure
|
39
41
|
DB.get{pg_advisory_unlock_all{}}
|
40
42
|
end
|
data/spec/unit/work_spec.rb
CHANGED
@@ -2,7 +2,7 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Que::Job, '.work' do
|
4
4
|
it "should pass a job's arguments to the run method and delete it from the database" do
|
5
|
-
ArgsJob.
|
5
|
+
ArgsJob.enqueue 1, 'two', {'three' => 3}
|
6
6
|
DB[:que_jobs].count.should be 1
|
7
7
|
|
8
8
|
result = Que::Job.work
|
@@ -13,9 +13,38 @@ describe Que::Job, '.work' do
|
|
13
13
|
$passed_args.should == [1, 'two', {'three' => 3}]
|
14
14
|
end
|
15
15
|
|
16
|
+
it "should default to only working jobs without a named queue" do
|
17
|
+
Que::Job.enqueue 1, :queue => 'other_queue'
|
18
|
+
Que::Job.enqueue 2
|
19
|
+
|
20
|
+
result = Que::Job.work
|
21
|
+
result[:event].should == :job_worked
|
22
|
+
result[:job][:args].should == [2]
|
23
|
+
|
24
|
+
result = Que::Job.work
|
25
|
+
result[:event].should == :job_unavailable
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should accept the name of a single queue to pull jobs from" do
|
29
|
+
Que::Job.enqueue 1, :queue => 'other_queue'
|
30
|
+
Que::Job.enqueue 2, :queue => 'other_queue'
|
31
|
+
Que::Job.enqueue 3
|
32
|
+
|
33
|
+
result = Que::Job.work(:other_queue)
|
34
|
+
result[:event].should == :job_worked
|
35
|
+
result[:job][:args].should == [1]
|
36
|
+
|
37
|
+
result = Que::Job.work('other_queue')
|
38
|
+
result[:event].should == :job_worked
|
39
|
+
result[:job][:args].should == [2]
|
40
|
+
|
41
|
+
result = Que::Job.work(:other_queue)
|
42
|
+
result[:event].should == :job_unavailable
|
43
|
+
end
|
44
|
+
|
16
45
|
it "should make a job's argument hashes indifferently accessible" do
|
17
46
|
DB[:que_jobs].count.should be 0
|
18
|
-
ArgsJob.
|
47
|
+
ArgsJob.enqueue 1, 'two', {'array' => [{'number' => 3}]}
|
19
48
|
DB[:que_jobs].count.should be 1
|
20
49
|
|
21
50
|
result = Que::Job.work
|
@@ -33,7 +62,7 @@ describe Que::Job, '.work' do
|
|
33
62
|
|
34
63
|
it "should prefer a job with a higher priority" do
|
35
64
|
# 1 is highest priority.
|
36
|
-
[5, 4, 3, 2, 1, 2, 3, 4, 5].map{|p| Que::Job.
|
65
|
+
[5, 4, 3, 2, 1, 2, 3, 4, 5].map{|p| Que::Job.enqueue :priority => p}
|
37
66
|
DB[:que_jobs].order(:job_id).select_map(:priority).should == [5, 4, 3, 2, 1, 2, 3, 4, 5]
|
38
67
|
|
39
68
|
result = Que::Job.work
|
@@ -43,9 +72,9 @@ describe Que::Job, '.work' do
|
|
43
72
|
end
|
44
73
|
|
45
74
|
it "should prefer a job that was scheduled to run longer ago when priorities are equal" do
|
46
|
-
Que::Job.
|
47
|
-
Que::Job.
|
48
|
-
Que::Job.
|
75
|
+
Que::Job.enqueue :run_at => Time.now - 30
|
76
|
+
Que::Job.enqueue :run_at => Time.now - 60
|
77
|
+
Que::Job.enqueue :run_at => Time.now - 30
|
49
78
|
|
50
79
|
recent1, old, recent2 = DB[:que_jobs].order(:job_id).select_map(:run_at)
|
51
80
|
|
@@ -57,9 +86,9 @@ describe Que::Job, '.work' do
|
|
57
86
|
|
58
87
|
it "should prefer a job that was queued earlier when priorities and run_ats are equal" do
|
59
88
|
run_at = Time.now - 30
|
60
|
-
Que::Job.
|
61
|
-
Que::Job.
|
62
|
-
Que::Job.
|
89
|
+
Que::Job.enqueue :run_at => run_at
|
90
|
+
Que::Job.enqueue :run_at => run_at
|
91
|
+
Que::Job.enqueue :run_at => run_at
|
63
92
|
|
64
93
|
first, second, third = DB[:que_jobs].select_order_map(:job_id)
|
65
94
|
|
@@ -70,9 +99,9 @@ describe Que::Job, '.work' do
|
|
70
99
|
end
|
71
100
|
|
72
101
|
it "should only work a job whose scheduled time to run has passed" do
|
73
|
-
Que::Job.
|
74
|
-
Que::Job.
|
75
|
-
Que::Job.
|
102
|
+
Que::Job.enqueue :run_at => Time.now + 30
|
103
|
+
Que::Job.enqueue :run_at => Time.now - 30
|
104
|
+
Que::Job.enqueue :run_at => Time.now + 30
|
76
105
|
|
77
106
|
future1, past, future2 = DB[:que_jobs].order(:job_id).select_map(:run_at)
|
78
107
|
|
@@ -84,7 +113,7 @@ describe Que::Job, '.work' do
|
|
84
113
|
end
|
85
114
|
|
86
115
|
it "should lock the job it selects" do
|
87
|
-
BlockJob.
|
116
|
+
BlockJob.enqueue
|
88
117
|
id = DB[:que_jobs].get(:job_id)
|
89
118
|
thread = Thread.new { Que::Job.work }
|
90
119
|
|
@@ -96,9 +125,9 @@ describe Que::Job, '.work' do
|
|
96
125
|
end
|
97
126
|
|
98
127
|
it "should skip jobs that are advisory-locked" do
|
99
|
-
Que::Job.
|
100
|
-
Que::Job.
|
101
|
-
Que::Job.
|
128
|
+
Que::Job.enqueue :priority => 2
|
129
|
+
Que::Job.enqueue :priority => 1
|
130
|
+
Que::Job.enqueue :priority => 3
|
102
131
|
id = DB[:que_jobs].where(:priority => 1).get(:job_id)
|
103
132
|
|
104
133
|
begin
|
@@ -116,7 +145,7 @@ describe Que::Job, '.work' do
|
|
116
145
|
|
117
146
|
it "should handle subclasses of other jobs" do
|
118
147
|
class SubClassJob < Que::Job
|
119
|
-
@
|
148
|
+
@priority = 2
|
120
149
|
|
121
150
|
def run
|
122
151
|
$job_spec_result << :sub
|
@@ -124,7 +153,7 @@ describe Que::Job, '.work' do
|
|
124
153
|
end
|
125
154
|
|
126
155
|
class SubSubClassJob < SubClassJob
|
127
|
-
@
|
156
|
+
@priority = 4
|
128
157
|
|
129
158
|
def run
|
130
159
|
super
|
@@ -133,7 +162,7 @@ describe Que::Job, '.work' do
|
|
133
162
|
end
|
134
163
|
|
135
164
|
$job_spec_result = []
|
136
|
-
SubClassJob.
|
165
|
+
SubClassJob.enqueue
|
137
166
|
DB[:que_jobs].select_map(:priority).should == [2]
|
138
167
|
result = Que::Job.work
|
139
168
|
result[:event].should == :job_worked
|
@@ -141,7 +170,7 @@ describe Que::Job, '.work' do
|
|
141
170
|
$job_spec_result.should == [:sub]
|
142
171
|
|
143
172
|
$job_spec_result = []
|
144
|
-
SubSubClassJob.
|
173
|
+
SubSubClassJob.enqueue
|
145
174
|
DB[:que_jobs].select_map(:priority).should == [4]
|
146
175
|
result = Que::Job.work
|
147
176
|
result[:event].should == :job_worked
|
@@ -155,7 +184,7 @@ describe Que::Job, '.work' do
|
|
155
184
|
end
|
156
185
|
end
|
157
186
|
|
158
|
-
ModuleJobModule::ModuleJob.
|
187
|
+
ModuleJobModule::ModuleJob.enqueue
|
159
188
|
DB[:que_jobs].get(:job_class).should == "ModuleJobModule::ModuleJob"
|
160
189
|
|
161
190
|
result = Que::Job.work
|
@@ -170,7 +199,7 @@ describe Que::Job, '.work' do
|
|
170
199
|
end
|
171
200
|
end
|
172
201
|
|
173
|
-
DestroyJob.
|
202
|
+
DestroyJob.enqueue
|
174
203
|
DB[:que_jobs].count.should be 1
|
175
204
|
Que::Job.work
|
176
205
|
DB[:que_jobs].count.should be 0
|
@@ -178,7 +207,7 @@ describe Que::Job, '.work' do
|
|
178
207
|
|
179
208
|
describe "when encountering an error" do
|
180
209
|
it "should exponentially back off the job" do
|
181
|
-
ErrorJob.
|
210
|
+
ErrorJob.enqueue
|
182
211
|
|
183
212
|
result = Que::Job.work
|
184
213
|
result[:event].should == :job_errored
|
@@ -206,12 +235,78 @@ describe Que::Job, '.work' do
|
|
206
235
|
job[:run_at].should be_within(3).of Time.now + 1299
|
207
236
|
end
|
208
237
|
|
238
|
+
it "should respect a custom retry interval" do
|
239
|
+
class RetryIntervalJob < ErrorJob
|
240
|
+
@retry_interval = 5
|
241
|
+
end
|
242
|
+
|
243
|
+
RetryIntervalJob.enqueue
|
244
|
+
|
245
|
+
result = Que::Job.work
|
246
|
+
result[:event].should == :job_errored
|
247
|
+
result[:error].should be_an_instance_of RuntimeError
|
248
|
+
result[:job][:job_class].should == 'RetryIntervalJob'
|
249
|
+
|
250
|
+
DB[:que_jobs].count.should be 1
|
251
|
+
job = DB[:que_jobs].first
|
252
|
+
job[:error_count].should be 1
|
253
|
+
job[:last_error].should =~ /\AErrorJob!\n/
|
254
|
+
job[:run_at].should be_within(3).of Time.now + 5
|
255
|
+
|
256
|
+
DB[:que_jobs].update :error_count => 5,
|
257
|
+
:run_at => Time.now - 60
|
258
|
+
|
259
|
+
result = Que::Job.work
|
260
|
+
result[:event].should == :job_errored
|
261
|
+
result[:error].should be_an_instance_of RuntimeError
|
262
|
+
result[:job][:job_class].should == 'RetryIntervalJob'
|
263
|
+
|
264
|
+
DB[:que_jobs].count.should be 1
|
265
|
+
job = DB[:que_jobs].first
|
266
|
+
job[:error_count].should be 6
|
267
|
+
job[:last_error].should =~ /\AErrorJob!\n/
|
268
|
+
job[:run_at].should be_within(3).of Time.now + 5
|
269
|
+
end
|
270
|
+
|
271
|
+
it "should respect a custom retry interval formula" do
|
272
|
+
class RetryIntervalFormulaJob < ErrorJob
|
273
|
+
@retry_interval = proc { |count| count * 10 }
|
274
|
+
end
|
275
|
+
|
276
|
+
RetryIntervalFormulaJob.enqueue
|
277
|
+
|
278
|
+
result = Que::Job.work
|
279
|
+
result[:event].should == :job_errored
|
280
|
+
result[:error].should be_an_instance_of RuntimeError
|
281
|
+
result[:job][:job_class].should == 'RetryIntervalFormulaJob'
|
282
|
+
|
283
|
+
DB[:que_jobs].count.should be 1
|
284
|
+
job = DB[:que_jobs].first
|
285
|
+
job[:error_count].should be 1
|
286
|
+
job[:last_error].should =~ /\AErrorJob!\n/
|
287
|
+
job[:run_at].should be_within(3).of Time.now + 10
|
288
|
+
|
289
|
+
DB[:que_jobs].update :error_count => 5,
|
290
|
+
:run_at => Time.now - 60
|
291
|
+
|
292
|
+
result = Que::Job.work
|
293
|
+
result[:event].should == :job_errored
|
294
|
+
result[:error].should be_an_instance_of RuntimeError
|
295
|
+
result[:job][:job_class].should == 'RetryIntervalFormulaJob'
|
296
|
+
|
297
|
+
DB[:que_jobs].count.should be 1
|
298
|
+
job = DB[:que_jobs].first
|
299
|
+
job[:error_count].should be 6
|
300
|
+
job[:last_error].should =~ /\AErrorJob!\n/
|
301
|
+
job[:run_at].should be_within(3).of Time.now + 60
|
302
|
+
end
|
303
|
+
|
209
304
|
it "should pass it to an error handler, if one is defined" do
|
210
305
|
begin
|
211
306
|
errors = []
|
212
307
|
Que.error_handler = proc { |error| errors << error }
|
213
308
|
|
214
|
-
ErrorJob.
|
309
|
+
ErrorJob.enqueue
|
215
310
|
|
216
311
|
result = Que::Job.work
|
217
312
|
result[:event].should == :job_errored
|
@@ -230,7 +325,7 @@ describe Que::Job, '.work' do
|
|
230
325
|
it "should not do anything if the error handler itelf throws an error" do
|
231
326
|
begin
|
232
327
|
Que.error_handler = proc { |error| raise "Another error!" }
|
233
|
-
ErrorJob.
|
328
|
+
ErrorJob.enqueue
|
234
329
|
|
235
330
|
result = Que::Job.work
|
236
331
|
result[:event].should == :job_errored
|