que 0.0.1 → 0.1.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.
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.0.1
4
+ version: 0.1.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: 2013-11-07 00:00:00.000000000 Z
11
+ date: 2013-11-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -73,7 +73,21 @@ dependencies:
73
73
  - - '>='
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
- type: :runtime
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: activerecord
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
@@ -87,14 +101,28 @@ dependencies:
87
101
  - - '>='
88
102
  - !ruby/object:Gem::Version
89
103
  version: '0'
90
- type: :runtime
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: connection_pool
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
91
119
  prerelease: false
92
120
  version_requirements: !ruby/object:Gem::Requirement
93
121
  requirements:
94
122
  - - '>='
95
123
  - !ruby/object:Gem::Version
96
124
  version: '0'
97
- description: Durable job queueing with PostgreSQL.
125
+ description: A job queue that uses PostgreSQL's advisory locks for speed and reliability.
98
126
  email:
99
127
  - christopher.m.hanks@gmail.com
100
128
  executables: []
@@ -107,17 +135,37 @@ files:
107
135
  - LICENSE.txt
108
136
  - README.md
109
137
  - Rakefile
138
+ - lib/generators/que/install_generator.rb
139
+ - lib/generators/que/templates/add_que.rb
110
140
  - lib/que.rb
141
+ - lib/que/adapters/active_record.rb
142
+ - lib/que/adapters/base.rb
143
+ - lib/que/adapters/connection_pool.rb
144
+ - lib/que/adapters/pg.rb
145
+ - lib/que/adapters/sequel.rb
111
146
  - lib/que/job.rb
147
+ - lib/que/railtie.rb
148
+ - lib/que/rake_tasks.rb
149
+ - lib/que/sql.rb
112
150
  - lib/que/version.rb
113
151
  - lib/que/worker.rb
114
152
  - que.gemspec
153
+ - spec/adapters/active_record_spec.rb
154
+ - spec/adapters/connection_pool_spec.rb
155
+ - spec/adapters/pg_spec.rb
156
+ - spec/adapters/sequel_spec.rb
157
+ - spec/connection_spec.rb
158
+ - spec/helper_spec.rb
159
+ - spec/pool_spec.rb
160
+ - spec/queue_spec.rb
115
161
  - spec/spec_helper.rb
116
- - spec/unit/error_spec.rb
117
- - spec/unit/queue_spec.rb
118
- - spec/unit/work_spec.rb
119
- - spec/unit/worker_spec.rb
120
- homepage: ''
162
+ - spec/support/helpers.rb
163
+ - spec/support/jobs.rb
164
+ - spec/support/shared_examples/adapter.rb
165
+ - spec/support/shared_examples/multithreaded_adapter.rb
166
+ - spec/work_spec.rb
167
+ - spec/worker_spec.rb
168
+ homepage: https://github.com/chanks/que
121
169
  licenses:
122
170
  - MIT
123
171
  metadata: {}
@@ -140,10 +188,20 @@ rubyforge_project:
140
188
  rubygems_version: 2.1.9
141
189
  signing_key:
142
190
  specification_version: 4
143
- summary: Durable, efficient job queueing with PostgreSQL.
191
+ summary: A PostgreSQL-based Job Queue
144
192
  test_files:
193
+ - spec/adapters/active_record_spec.rb
194
+ - spec/adapters/connection_pool_spec.rb
195
+ - spec/adapters/pg_spec.rb
196
+ - spec/adapters/sequel_spec.rb
197
+ - spec/connection_spec.rb
198
+ - spec/helper_spec.rb
199
+ - spec/pool_spec.rb
200
+ - spec/queue_spec.rb
145
201
  - spec/spec_helper.rb
146
- - spec/unit/error_spec.rb
147
- - spec/unit/queue_spec.rb
148
- - spec/unit/work_spec.rb
149
- - spec/unit/worker_spec.rb
202
+ - spec/support/helpers.rb
203
+ - spec/support/jobs.rb
204
+ - spec/support/shared_examples/adapter.rb
205
+ - spec/support/shared_examples/multithreaded_adapter.rb
206
+ - spec/work_spec.rb
207
+ - spec/worker_spec.rb
@@ -1,45 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe "Que::Job error handling" do
4
- class ErrorJob < Que::Job
5
- def perform(*args)
6
- raise "Boo!"
7
- end
8
- end
9
-
10
- it "should increment the error_count, persist the error message and reschedule the job" do
11
- ErrorJob.queue
12
-
13
- proc { Que::Job.work }.should raise_error RuntimeError, "Boo!"
14
- Que::Job.count.should be 1
15
-
16
- job = Que::Job.first
17
- data = JSON.load(job.data)
18
- data['error_count'].should be 1
19
- data['error_message'].should =~ /Boo!/
20
- job.run_at.should be_within(1).of Time.now + 4
21
- end
22
-
23
- it "should reschedule jobs with exponentially increasing times" do
24
- ErrorJob.queue
25
- Que::Job.dataset.update :data => JSON.dump(:error_count => 5)
26
-
27
- proc { Que::Job.work }.should raise_error RuntimeError, "Boo!"
28
- Que::Job.count.should be 1
29
-
30
- job = Que::Job.first
31
- data = JSON.load(job.data)
32
- data['error_count'].should be 6
33
- data['error_message'].should =~ /Boo!/
34
- job.run_at.should be_within(1).of Time.now + 1299
35
- end
36
-
37
- it "should handle errors from jobs that cannot be deserialized" do
38
- DB[:jobs].insert :type => 'NonexistentJob', :priority => 1
39
- proc { Que::Job.work }.should raise_error NameError, /uninitialized constant NonexistentJob/
40
-
41
- job = DB[:jobs].first
42
- JSON.load(job[:data])['error_count'].should be 1
43
- job[:run_at].should be_within(1).of Time.now + 4
44
- end
45
- end
@@ -1,67 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe "Que::Job.queue" do
4
- it "should create a job in the DB" do
5
- Que::Job.queue :param1 => 4, :param2 => 'ferret', :param3 => false
6
- Que::Job.count.should == 1
7
-
8
- job = Que::Job.first
9
- job.type.should == 'Que::Job'
10
- job.run_at.should be_within(1).of Time.now
11
- job.priority.should be 5 # Defaults to lowest priority.
12
- JSON.load(job.args).should == [{'param1' => 4, 'param2' => 'ferret', 'param3' => false}]
13
- end
14
-
15
- it "should accept a :run_at argument" do
16
- time = Time.at(Time.now.to_i)
17
- Que::Job.queue :user_id => 4, :test_number => 8, :run_at => time
18
-
19
- Que::Job.count.should == 1
20
- job = Que::Job.first
21
- job.type.should == 'Que::Job'
22
- job.run_at.should == time
23
- job.priority.should == 5
24
- JSON.load(job.args).should == [{'user_id' => 4, 'test_number' => 8}]
25
- end
26
-
27
- it "should accept a :priority argument" do
28
- Que::Job.queue :user_id => 4, :test_number => 8, :priority => 1
29
-
30
- Que::Job.count.should == 1
31
- job = Que::Job.first
32
- job.type.should == 'Que::Job'
33
- job.run_at.should be_within(1).of Time.now
34
- job.priority.should be 1
35
- JSON.load(job.args).should == [{'user_id' => 4, 'test_number' => 8}]
36
- end
37
-
38
- it "should respect a default_priority for the class" do
39
- class TestPriorityJob < Que::Job
40
- @default_priority = 2
41
- end
42
-
43
- TestPriorityJob.queue :user_id => 4, :test_number => 8
44
-
45
- Que::Job.count.should == 1
46
- job = Que::Job.first
47
- job.type.should == 'TestPriorityJob'
48
- job.run_at.should be_within(1).of Time.now
49
- job.priority.should be 2
50
- JSON.load(job.args).should == [{'user_id' => 4, 'test_number' => 8}]
51
- end
52
-
53
- it "should let a :priority option override a default_priority for the class" do
54
- class OtherTestPriorityJob < Que::Job
55
- @default_priority = 2
56
- end
57
-
58
- OtherTestPriorityJob.queue :user_id => 4, :test_number => 8, :priority => 4
59
-
60
- Que::Job.count.should == 1
61
- job = Que::Job.first
62
- job.type.should == 'OtherTestPriorityJob'
63
- job.run_at.should be_within(1).of Time.now
64
- job.priority.should be 4
65
- JSON.load(job.args).should == [{'user_id' => 4, 'test_number' => 8}]
66
- end
67
- end
@@ -1,168 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe "Que::Job.work" do
4
- it "should automatically delete jobs from the database's queue" do
5
- Que::Job.count.should be 0
6
- Que::Job.queue
7
- Que::Job.count.should be 1
8
- Que::Job.work
9
- Que::Job.count.should be 0
10
- end
11
-
12
- it "should pass a job's arguments to its perform method" do
13
- class JobWorkTest < Que::Job
14
- def perform(*args)
15
- $passed_args = args
16
- end
17
- end
18
-
19
- JobWorkTest.queue 5, 'ferret', :lazy => true
20
-
21
- Que::Job.work
22
- $passed_args.should == [5, 'ferret', {'lazy' => true}]
23
- end
24
-
25
- it "should prefer a job with higher priority" do
26
- Que::Job.queue
27
- Que::Job.queue :priority => 1
28
-
29
- Que::Job.select_order_map(:priority).should == [1, 5]
30
- Que::Job.work
31
- Que::Job.select_order_map(:priority).should == [5]
32
- end
33
-
34
- it "should prefer a job that was scheduled to run longer ago" do
35
- now = Time.at(Time.now.to_i) # Prevent rounding errors by rounding to the nearest second.
36
- recently = now - 60
37
- long_ago = now - 61
38
-
39
- Que::Job.queue :run_at => recently
40
- Que::Job.queue :run_at => long_ago
41
-
42
- Que::Job.select_order_map(:run_at).should == [long_ago, recently]
43
- Que::Job.work
44
- Que::Job.select_order_map(:run_at).should == [recently]
45
- end
46
-
47
- it "should only work a job whose run_at has already passed" do
48
- now = Time.at(Time.now.to_i) # Prevent rounding errors by rounding to the nearest second.
49
- past = now - 60
50
- soon = now + 60
51
-
52
- Que::Job.queue :run_at => past
53
- Que::Job.queue :run_at => soon
54
-
55
- Que::Job.select_order_map(:run_at).should == [past, soon]
56
- Que::Job.work
57
- Que::Job.select_order_map(:run_at).should == [soon]
58
- Que::Job.work
59
- Que::Job.select_order_map(:run_at).should == [soon]
60
- end
61
-
62
- it "should prefer a job that was scheduled earlier, and therefore has a lower job_id" do
63
- time = Time.now - 60
64
- Que::Job.queue :run_at => time
65
- Que::Job.queue :run_at => time
66
-
67
- a, b = Que::Job.select_order_map(:job_id)
68
- Que::Job.work
69
- Que::Job.select_order_map(:job_id).should == [b]
70
- end
71
-
72
- it "should lock the job it selects" do
73
- $q1, $q2 = Queue.new, Queue.new
74
-
75
- class LockJob < Que::Job
76
- def perform(*args)
77
- $q1.push nil
78
- $q2.pop
79
- end
80
- end
81
-
82
- job = LockJob.queue
83
- @thread = Thread.new { Que::Job.work }
84
-
85
- # Wait until job is being worked.
86
- $q1.pop
87
-
88
- # Job should be advisory-locked...
89
- DB.select{pg_try_advisory_lock(job.job_id)}.single_value.should be false
90
-
91
- # ...and Job.work should ignore advisory-locked jobs.
92
- Que::Job.work.should be nil
93
-
94
- # Let LockJob finish.
95
- $q2.push nil
96
-
97
- # Make sure there aren't any errors.
98
- @thread.join
99
- end
100
-
101
- it "that raises a Que::Job::Retry should abort the job, leaving it to be retried" do
102
- class RetryJob < Que::Job
103
- def perform(*args)
104
- raise Que::Job::Retry
105
- end
106
- end
107
-
108
- job = RetryJob.queue
109
- Que::Job.count.should be 1
110
- Que::Job.work
111
- Que::Job.count.should be 1
112
-
113
- same_job = Que::Job.first
114
- same_job.job_id.should == job.job_id
115
- same_job.run_at.should == job.run_at
116
- same_job.data['error_count'].should be nil
117
- end
118
-
119
- it "should handle subclasses of other jobs" do
120
- $class_job_array = []
121
-
122
- class ClassJob < Que::Job
123
- def perform(*args)
124
- $class_job_array << 2
125
- end
126
- end
127
-
128
- class SubclassJob < ClassJob
129
- def perform(*args)
130
- $class_job_array << 1
131
- super
132
- end
133
- end
134
-
135
- SubclassJob.queue
136
- Que::Job.get(:type).should == 'SubclassJob'
137
- Que::Job.work
138
- $class_job_array.should == [1, 2]
139
- end
140
-
141
- describe "should support a logger" do
142
- before do
143
- @logger = Object.new
144
- def @logger.method_missing(m, message)
145
- @messages ||= []
146
- @messages << message
147
- end
148
- Que.logger = @logger
149
- end
150
-
151
- after do
152
- Que.logger = nil
153
- end
154
-
155
- def messages
156
- @logger.instance_variable_get(:@messages)
157
- end
158
-
159
- it "should write messages to the logger" do
160
- Que::Job.queue
161
- Que::Job.work
162
-
163
- messages.should be_an_instance_of Array
164
- messages.length.should == 1
165
- messages[0].should =~ /\AWorked job in/
166
- end
167
- end
168
- end
@@ -1,31 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Que::Worker do
4
- class ExceptionJob < Que::Job
5
- def perform(*args)
6
- raise "Blah!"
7
- end
8
- end
9
-
10
- it "should not be taken out by an error, and keep looking for jobs" do
11
- ExceptionJob.queue
12
- Que::Job.queue
13
-
14
- Que::Worker.state = :async
15
- Que::Worker.wake!
16
- @worker = Que::Worker.workers.first
17
-
18
- {} until @worker.thread[:state] == :sleeping
19
-
20
- # Job was worked, ExceptionJob remains.
21
- Que::Job.select_map(:type).should == ['ExceptionJob']
22
- end
23
-
24
- it "#async? and #up? should return whether Worker is async and whether there are workers running, respectively" do
25
- Que::Worker.should_not be_async
26
- Que::Worker.should_not be_up
27
- Que::Worker.state = :async
28
- Que::Worker.should be_async
29
- Que::Worker.should be_up
30
- end
31
- end