que 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -7,11 +7,11 @@ describe Que::Job, '.queue' do
7
7
  DB[:que_jobs].count.should be 1
8
8
 
9
9
  result.should be_an_instance_of Que::Job
10
- result.attrs[:priority].should == '1'
10
+ result.attrs[:priority].should == '100'
11
11
  result.attrs[:args].should == []
12
12
 
13
13
  job = DB[:que_jobs].first
14
- job[:priority].should be 1
14
+ job[:priority].should be 100
15
15
  job[:run_at].should be_within(3).of Time.now
16
16
  job[:job_class].should == "Que::Job"
17
17
  JSON.load(job[:args]).should == []
@@ -23,7 +23,7 @@ describe Que::Job, '.queue' do
23
23
  DB[:que_jobs].count.should be 1
24
24
 
25
25
  job = DB[:que_jobs].first
26
- job[:priority].should be 1
26
+ job[:priority].should be 100
27
27
  job[:run_at].should be_within(3).of Time.now
28
28
  job[:job_class].should == "Que::Job"
29
29
  JSON.load(job[:args]).should == [1, 'two']
@@ -39,7 +39,7 @@ describe Que::Job, '.queue' do
39
39
  DB[:que_jobs].count.should be 1
40
40
 
41
41
  job = DB[:que_jobs].first
42
- job[:priority].should be 1
42
+ job[:priority].should be 100
43
43
  job[:run_at].should be_within(3).of Time.now
44
44
  job[:job_class].should == "Que::Job"
45
45
  JSON.load(job[:args]).should == [
@@ -60,7 +60,7 @@ describe Que::Job, '.queue' do
60
60
  DB[:que_jobs].count.should be 1
61
61
 
62
62
  job = DB[:que_jobs].first
63
- job[:priority].should be 1
63
+ job[:priority].should be 100
64
64
  job[:run_at].should be_within(3).of Time.now + 60
65
65
  job[:job_class].should == "Que::Job"
66
66
  JSON.load(job[:args]).should == [1]
@@ -125,12 +125,12 @@ describe Que::Job, '.queue' do
125
125
 
126
126
  first, second = DB[:que_jobs].order(:job_id).all
127
127
 
128
- first[:priority].should be 1
128
+ first[:priority].should be 100
129
129
  first[:run_at].should be_within(3).of Time.now + 60
130
130
  first[:job_class].should == "DefaultRunAtJob"
131
131
  JSON.load(first[:args]).should == [1]
132
132
 
133
- second[:priority].should be 1
133
+ second[:priority].should be 100
134
134
  second[:run_at].should be_within(3).of Time.now + 30
135
135
  second[:job_class].should == "DefaultRunAtJob"
136
136
  JSON.load(second[:args]).should == [1]
@@ -24,6 +24,9 @@ describe Que, '.worker_states' do
24
24
  states = Que.worker_states
25
25
  states.length.should be 1
26
26
 
27
+ $q2.push nil
28
+ t.join
29
+
27
30
  state = states.first
28
31
  state.keys.should == %w(priority run_at job_id job_class args error_count last_error 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)
29
32
 
@@ -42,11 +45,6 @@ describe Que, '.worker_states' do
42
45
  Time.parse(state[:pg_last_query_started_at]).should be_within(3).of Time.now
43
46
  state[:pg_transaction_started_at].should == nil
44
47
  state[:pg_waiting_on_lock].should == 'f'
45
- ensure
46
- if t
47
- t.kill
48
- t.join
49
- end
50
48
  end
51
49
  end if QUE_ADAPTERS[:connection_pool]
52
50
  end
@@ -4,7 +4,11 @@ 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
5
  ArgsJob.queue 1, 'two', {'three' => 3}
6
6
  DB[:que_jobs].count.should be 1
7
- Que::Job.work.should be_an_instance_of ArgsJob
7
+
8
+ result = Que::Job.work
9
+ result[:event].should == :job_worked
10
+ result[:job][:job_class].should == 'ArgsJob'
11
+
8
12
  DB[:que_jobs].count.should be 0
9
13
  $passed_args.should == [1, 'two', {'three' => 3}]
10
14
  end
@@ -13,33 +17,18 @@ describe Que::Job, '.work' do
13
17
  DB[:que_jobs].count.should be 0
14
18
  ArgsJob.queue 1, 'two', {'array' => [{'number' => 3}]}
15
19
  DB[:que_jobs].count.should be 1
16
- Que::Job.work.should be_an_instance_of ArgsJob
20
+
21
+ result = Que::Job.work
22
+ result[:event].should == :job_worked
23
+ result[:job][:job_class].should == 'ArgsJob'
24
+
17
25
  DB[:que_jobs].count.should be 0
18
26
 
19
27
  $passed_args.last[:array].first[:number].should == 3
20
28
  end
21
29
 
22
30
  it "should not fail if there are no jobs to work" do
23
- Que::Job.work.should be nil
24
- end
25
-
26
- it "should write messages to the logger" do
27
- Que::Job.queue
28
- Que::Job.work
29
-
30
- $logger.messages.length.should == 1
31
- $logger.messages[0].should =~ /\A\[Que\] Worked job in/
32
- end
33
-
34
- it "should not fail if there's no logger assigned" do
35
- begin
36
- Que.logger = nil
37
-
38
- Que::Job.queue
39
- Que::Job.work
40
- ensure
41
- Que.logger = $logger
42
- end
31
+ Que::Job.work[:event].should be :job_unavailable
43
32
  end
44
33
 
45
34
  it "should prefer a job with a higher priority" do
@@ -47,7 +36,9 @@ describe Que::Job, '.work' do
47
36
  [5, 4, 3, 2, 1, 2, 3, 4, 5].map{|p| Que::Job.queue :priority => p}
48
37
  DB[:que_jobs].order(:job_id).select_map(:priority).should == [5, 4, 3, 2, 1, 2, 3, 4, 5]
49
38
 
50
- Que::Job.work.should be_an_instance_of Que::Job
39
+ result = Que::Job.work
40
+ result[:event].should == :job_worked
41
+ result[:job][:job_class].should == 'Que::Job'
51
42
  DB[:que_jobs].select_map(:priority).should == [5, 4, 3, 2, 2, 3, 4, 5]
52
43
  end
53
44
 
@@ -58,7 +49,9 @@ describe Que::Job, '.work' do
58
49
 
59
50
  recent1, old, recent2 = DB[:que_jobs].order(:job_id).select_map(:run_at)
60
51
 
61
- Que::Job.work.should be_an_instance_of Que::Job
52
+ result = Que::Job.work
53
+ result[:event].should == :job_worked
54
+ result[:job][:job_class].should == 'Que::Job'
62
55
  DB[:que_jobs].order_by(:job_id).select_map(:run_at).should == [recent1, recent2]
63
56
  end
64
57
 
@@ -70,7 +63,9 @@ describe Que::Job, '.work' do
70
63
 
71
64
  first, second, third = DB[:que_jobs].select_order_map(:job_id)
72
65
 
73
- Que::Job.work.should be_an_instance_of Que::Job
66
+ result = Que::Job.work
67
+ result[:event].should == :job_worked
68
+ result[:job][:job_class].should == 'Que::Job'
74
69
  DB[:que_jobs].select_order_map(:job_id).should == [second, third]
75
70
  end
76
71
 
@@ -81,8 +76,10 @@ describe Que::Job, '.work' do
81
76
 
82
77
  future1, past, future2 = DB[:que_jobs].order(:job_id).select_map(:run_at)
83
78
 
84
- Que::Job.work.should be_an_instance_of Que::Job
85
- Que::Job.work.should be nil
79
+ result = Que::Job.work
80
+ result[:event].should == :job_worked
81
+ result[:job][:job_class].should == 'Que::Job'
82
+ Que::Job.work[:event].should be :job_unavailable
86
83
  DB[:que_jobs].order_by(:job_id).select_map(:run_at).should == [future1, future2]
87
84
  end
88
85
 
@@ -106,7 +103,11 @@ describe Que::Job, '.work' do
106
103
 
107
104
  begin
108
105
  DB.select{pg_advisory_lock(id)}.single_value
109
- Que::Job.work.should be_an_instance_of Que::Job
106
+
107
+ result = Que::Job.work
108
+ result[:event].should == :job_worked
109
+ result[:job][:job_class].should == 'Que::Job'
110
+
110
111
  DB[:que_jobs].order_by(:job_id).select_map(:priority).should == [1, 3]
111
112
  ensure
112
113
  DB.select{pg_advisory_unlock(id)}.single_value
@@ -134,13 +135,17 @@ describe Que::Job, '.work' do
134
135
  $job_spec_result = []
135
136
  SubClassJob.queue
136
137
  DB[:que_jobs].select_map(:priority).should == [2]
137
- Que::Job.work.should be_an_instance_of SubClassJob
138
+ result = Que::Job.work
139
+ result[:event].should == :job_worked
140
+ result[:job][:job_class].should == 'SubClassJob'
138
141
  $job_spec_result.should == [:sub]
139
142
 
140
143
  $job_spec_result = []
141
144
  SubSubClassJob.queue
142
145
  DB[:que_jobs].select_map(:priority).should == [4]
143
- Que::Job.work.should be_an_instance_of SubSubClassJob
146
+ result = Que::Job.work
147
+ result[:event].should == :job_worked
148
+ result[:job][:job_class].should == 'SubSubClassJob'
144
149
  $job_spec_result.should == [:sub, :subsub]
145
150
  end
146
151
 
@@ -152,7 +157,10 @@ describe Que::Job, '.work' do
152
157
 
153
158
  ModuleJobModule::ModuleJob.queue
154
159
  DB[:que_jobs].get(:job_class).should == "ModuleJobModule::ModuleJob"
155
- Que::Job.work.should be_an_instance_of ModuleJobModule::ModuleJob
160
+
161
+ result = Que::Job.work
162
+ result[:event].should == :job_worked
163
+ result[:job][:job_class].should == 'ModuleJobModule::ModuleJob'
156
164
  end
157
165
 
158
166
  it "should make it easy to destroy the job within the same transaction as other changes" do
@@ -171,7 +179,11 @@ describe Que::Job, '.work' do
171
179
  describe "when encountering an error" do
172
180
  it "should exponentially back off the job" do
173
181
  ErrorJob.queue
174
- Que::Job.work.should be true
182
+
183
+ result = Que::Job.work
184
+ result[:event].should == :job_errored
185
+ result[:error].should be_an_instance_of RuntimeError
186
+ result[:job][:job_class].should == 'ErrorJob'
175
187
 
176
188
  DB[:que_jobs].count.should be 1
177
189
  job = DB[:que_jobs].first
@@ -182,7 +194,10 @@ describe Que::Job, '.work' do
182
194
  DB[:que_jobs].update :error_count => 5,
183
195
  :run_at => Time.now - 60
184
196
 
185
- Que::Job.work.should be true
197
+ result = Que::Job.work
198
+ result[:event].should == :job_errored
199
+ result[:error].should be_an_instance_of RuntimeError
200
+ result[:job][:job_class].should == 'ErrorJob'
186
201
 
187
202
  DB[:que_jobs].count.should be 1
188
203
  job = DB[:que_jobs].first
@@ -197,7 +212,11 @@ describe Que::Job, '.work' do
197
212
  Que.error_handler = proc { |error| errors << error }
198
213
 
199
214
  ErrorJob.queue
200
- Que::Job.work.should be true
215
+
216
+ result = Que::Job.work
217
+ result[:event].should == :job_errored
218
+ result[:error].should be_an_instance_of RuntimeError
219
+ result[:job][:job_class].should == 'ErrorJob'
201
220
 
202
221
  errors.count.should be 1
203
222
  error = errors[0]
@@ -212,26 +231,23 @@ describe Que::Job, '.work' do
212
231
  begin
213
232
  Que.error_handler = proc { |error| raise "Another error!" }
214
233
  ErrorJob.queue
215
- Que::Job.work.should be true
234
+
235
+ result = Que::Job.work
236
+ result[:event].should == :job_errored
237
+ result[:error].should be_an_instance_of RuntimeError
216
238
  ensure
217
239
  Que.error_handler = nil
218
240
  end
219
241
  end
220
242
 
221
- it "should return false if the job throws a postgres error" do
222
- class PGErrorJob < Que::Job
223
- def run
224
- Que.execute "bad SQL syntax"
225
- end
226
- end
227
-
228
- PGErrorJob.queue
229
- Que::Job.work.should be false
230
- end
231
-
232
243
  it "should throw an error properly if there's no corresponding job class" do
233
244
  DB[:que_jobs].insert :job_class => "NonexistentClass"
234
- Que::Job.work.should be true
245
+
246
+ result = Que::Job.work
247
+ result[:event].should == :job_errored
248
+ result[:error].should be_an_instance_of NameError
249
+ result[:job][:job_class].should == 'NonexistentClass'
250
+
235
251
  DB[:que_jobs].count.should be 1
236
252
  job = DB[:que_jobs].first
237
253
  job[:error_count].should be 1
@@ -10,10 +10,15 @@ describe Que::Worker do
10
10
  @worker = Que::Worker.new
11
11
  sleep_until { @worker.sleeping? }
12
12
  DB[:que_jobs].count.should be 0
13
+
14
+ $logger.messages.map{|m| JSON.load(m)['event']}.should == %w(job_worked job_worked job_unavailable)
15
+
16
+ json = JSON.load($logger.messages[0])
17
+ json['job']['job_class'].should == 'Que::Job'
13
18
  ensure
14
19
  if @worker
15
- @worker.thread.kill
16
- @worker.thread.join
20
+ @worker.stop
21
+ @worker.wait_until_stopped
17
22
  end
18
23
  end
19
24
  end
@@ -32,8 +37,8 @@ describe Que::Worker do
32
37
  DB[:que_jobs].count.should be 0
33
38
  ensure
34
39
  if @worker
35
- @worker.thread.kill
36
- @worker.thread.join
40
+ @worker.stop
41
+ @worker.wait_until_stopped
37
42
  end
38
43
  end
39
44
  end
@@ -46,10 +51,11 @@ describe Que::Worker do
46
51
  $q1.pop
47
52
  DB[:que_jobs].count.should be 1
48
53
  @worker.wake!.should be nil
54
+ $q2.push nil
49
55
  ensure
50
56
  if @worker
51
- @worker.thread.kill
52
- @worker.thread.join
57
+ @worker.stop
58
+ @worker.wait_until_stopped
53
59
  end
54
60
  end
55
61
  end
@@ -67,10 +73,16 @@ describe Que::Worker do
67
73
  job = DB[:que_jobs].first
68
74
  job[:job_class].should == 'ErrorJob'
69
75
  job[:run_at].should be_within(3).of Time.now + 4
76
+
77
+ log = JSON.load($logger.messages[0])
78
+ log['event'].should == 'job_errored'
79
+ log['error']['class'].should == 'RuntimeError'
80
+ log['error']['message'].should == "ErrorJob!"
81
+ log['job']['job_class'].should == 'ErrorJob'
70
82
  ensure
71
83
  if @worker
72
- @worker.thread.kill
73
- @worker.thread.join
84
+ @worker.stop
85
+ @worker.wait_until_stopped
74
86
  end
75
87
  end
76
88
  end
@@ -92,11 +104,6 @@ describe Que::Worker do
92
104
  DB[:que_jobs].count.should be 1
93
105
  job = DB[:que_jobs].first
94
106
  job[:job_class].should == 'Que::Job'
95
- ensure
96
- if @worker
97
- @worker.thread.kill
98
- @worker.thread.join
99
- end
100
107
  end
101
108
  end
102
109
 
@@ -107,45 +114,6 @@ describe Que::Worker do
107
114
 
108
115
  @worker.stop
109
116
  @worker.wait_until_stopped
110
- ensure
111
- if @worker
112
- @worker.thread.kill
113
- @worker.thread.join
114
- end
115
- end
116
- end
117
-
118
- it "should receive and respect a notification to stop immediately when it is working, and kill the job" do
119
- begin
120
- # Worker#stop! can leave the database connection in an unpredictable
121
- # state, which would impact the rest of the tests, so we need a special
122
- # connection for it.
123
- pg = NEW_PG_CONNECTION.call
124
- Que.connection = pg
125
-
126
- BlockJob.queue
127
-
128
- @worker = Que::Worker.new
129
- $q1.pop
130
- @worker.stop!
131
- @worker.wait_until_stopped
132
- ensure
133
- pg.close if pg
134
- end
135
- end
136
-
137
- it "should receive and respect a notification to stop immediately when it is currently asleep" do
138
- begin
139
- @worker = Que::Worker.new
140
- sleep_until { @worker.sleeping? }
141
-
142
- @worker.stop!
143
- @worker.wait_until_stopped
144
- ensure
145
- if @worker
146
- @worker.thread.kill
147
- @worker.thread.join
148
- end
149
117
  end
150
118
  end
151
119
  end
@@ -49,15 +49,15 @@ task :safe_shutdown do
49
49
  puts "kill -#{signal} #{Process.pid}"
50
50
  end
51
51
 
52
- # Put exit behavior to test the behavior of here:
53
- at_exit do
54
- puts "Stopping Que..."
55
- Que.stop!
56
- end
57
-
58
52
  stop = false
59
53
  trap('INT'){stop = true}
60
54
 
55
+ at_exit do
56
+ $stdout.puts "Finishing Que's current jobs before exiting..."
57
+ Que.mode = :off
58
+ $stdout.puts "Que's jobs finished, exiting..."
59
+ end
60
+
61
61
  loop do
62
62
  sleep 0.01
63
63
  break if stop
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: que
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Hanks
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-06 00:00:00.000000000 Z
11
+ date: 2014-01-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -18,26 +18,12 @@ dependencies:
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.3'
20
20
  type: :development
21
- prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
23
  - - "~>"
25
24
  - !ruby/object:Gem::Version
26
25
  version: '1.3'
27
- - !ruby/object:Gem::Dependency
28
- name: multi_json
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '1.0'
34
- type: :runtime
35
26
  prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '1.0'
41
27
  description: A job queue that uses PostgreSQL's advisory locks for speed and reliability.
42
28
  email:
43
29
  - christopher.m.hanks@gmail.com
@@ -47,14 +33,17 @@ extra_rdoc_files: []
47
33
  files:
48
34
  - ".gitignore"
49
35
  - ".rspec"
36
+ - ".travis.yml"
50
37
  - CHANGELOG.md
51
38
  - Gemfile
52
39
  - LICENSE.txt
53
40
  - README.md
54
41
  - Rakefile
55
42
  - docs/advanced_setup.md
43
+ - docs/customizing_que.md
56
44
  - docs/error_handling.md
57
45
  - docs/inspecting_the_queue.md
46
+ - docs/logging.md
58
47
  - docs/managing_workers.md
59
48
  - docs/using_plain_connections.md
60
49
  - docs/using_sequel.md
@@ -68,6 +57,11 @@ files:
68
57
  - lib/que/adapters/pg.rb
69
58
  - lib/que/adapters/sequel.rb
70
59
  - lib/que/job.rb
60
+ - lib/que/migrations.rb
61
+ - lib/que/migrations/1-down.sql
62
+ - lib/que/migrations/1-up.sql
63
+ - lib/que/migrations/2-down.sql
64
+ - lib/que/migrations/2-up.sql
71
65
  - lib/que/railtie.rb
72
66
  - lib/que/rake_tasks.rb
73
67
  - lib/que/sql.rb
@@ -83,8 +77,11 @@ files:
83
77
  - spec/support/jobs.rb
84
78
  - spec/support/shared_examples/adapter.rb
85
79
  - spec/support/shared_examples/multi_threaded_adapter.rb
80
+ - spec/travis.rb
86
81
  - spec/unit/connection_spec.rb
87
82
  - spec/unit/helper_spec.rb
83
+ - spec/unit/logging_spec.rb
84
+ - spec/unit/migrations_spec.rb
88
85
  - spec/unit/pool_spec.rb
89
86
  - spec/unit/queue_spec.rb
90
87
  - spec/unit/states_spec.rb
@@ -114,7 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
114
111
  version: '0'
115
112
  requirements: []
116
113
  rubyforge_project:
117
- rubygems_version: 2.2.0.rc.1
114
+ rubygems_version: 2.1.5
118
115
  signing_key:
119
116
  specification_version: 4
120
117
  summary: A PostgreSQL-based Job Queue
@@ -128,8 +125,11 @@ test_files:
128
125
  - spec/support/jobs.rb
129
126
  - spec/support/shared_examples/adapter.rb
130
127
  - spec/support/shared_examples/multi_threaded_adapter.rb
128
+ - spec/travis.rb
131
129
  - spec/unit/connection_spec.rb
132
130
  - spec/unit/helper_spec.rb
131
+ - spec/unit/logging_spec.rb
132
+ - spec/unit/migrations_spec.rb
133
133
  - spec/unit/pool_spec.rb
134
134
  - spec/unit/queue_spec.rb
135
135
  - spec/unit/states_spec.rb