boss_queue 0.1.10 → 0.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.
data/README.md CHANGED
@@ -19,21 +19,25 @@ boss_queue uses an Amazon SQS queue and a Amazon DynamoDB table for each environ
19
19
  AWS.config(:access_key_id => <access_key_id>,
20
20
  :secret_access_key => <secret_access_key>)
21
21
 
22
+ queue = BossQueue.new # default queue name
23
+ # or
24
+ queue = BossQueue.new(:queue => 'emails') # customized queue name (so you can have separate job queues)
25
+
22
26
  BossQueue.environment = 'development'
23
- BossQueue.create_table
24
- BossQueue.create_queue
27
+ queue.create_table
28
+ queue.create_queue
25
29
 
26
30
  BossQueue.environment = 'staging'
27
- BossQueue.create_table
28
- BossQueue.create_queue
31
+ queue.create_table
32
+ queue.create_queue
29
33
 
30
34
  # BossQueue.create_table(read_capacity, write_capacity)
31
35
  # One read capacity unit = two eventually consistent reads per second, for items up 4 KB in size.
32
36
  # One write capacity unit = one write per second, for items up to 1 KB in size.
33
37
 
34
38
  BossQueue.environment = 'production'
35
- BossQueue.create_table(50, 10)
36
- BossQueue.create_queue
39
+ queue.create_table(50, 10)
40
+ queue.create_queue
37
41
 
38
42
 
39
43
  Alternatively, in each of the respective environments, do:
@@ -55,18 +59,19 @@ Usage
55
59
  =====
56
60
 
57
61
  myobject = MyClass.new
58
- BossQueue.failure_action = 'none' # default is 'retry' which retries up to four times
62
+ # default failure action is 'retry' which retries up to four times
63
+ queue = BossQueue.new(:failure_action => 'none', :queue => 'emails')
59
64
 
60
65
  # can enqueue instance methods (assumes that objects have an id and a #find(id) method)
61
- BossQueue.enqueue(myobject, :method_to_execute, arg1, arg2)
66
+ queue.enqueue(myobject, :method_to_execute, arg1, arg2)
62
67
  # enqueue with a delay of up to 900 seconds (15 minutes)
63
- BossQueue.enqueue_with_delay(60, myobject, :method_to_execute, arg1, arg2, arg3)
68
+ queue.enqueue_with_delay(60, myobject, :method_to_execute, arg1, arg2, arg3)
64
69
 
65
70
  # can enqueue class methods
66
- BossQueue.enqueue(MyClass, :method_to_execute)
67
- BossQueue.enqueue_with_delay(60, MyClass, :method_to_execute, arg1, arg2)
71
+ queue.enqueue(MyClass, :method_to_execute)
72
+ queue.enqueue_with_delay(60, MyClass, :method_to_execute, arg1, arg2)
68
73
 
69
- BossQueue.work
74
+ queue.work
70
75
 
71
76
  # failures are left in the DynamoDB table with the failed boolean set to true
72
77
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.10
1
+ 0.2.0
data/boss_queue.gemspec CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "boss_queue"
8
- s.version = "0.1.10"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Daniel Nelson"]
@@ -1,50 +1,48 @@
1
1
  require 'json'
2
2
 
3
3
  class BossQueue
4
- @@environment
4
+ @@environment = nil
5
5
 
6
- def self.environment=(env)
7
- @@environment = env
6
+ def initialize(options={})
7
+ @failure_action = options[:failure_action] if options[:failure_action]
8
+ @queue_postfix = options[:queue] ? '_' + options[:queue] : ''
8
9
  end
9
10
 
10
- @@failure_action
11
-
12
- def self.failure_action
13
- @@failure_action ||= 'retry'
11
+ def self.environment=(env)
12
+ @@environment = env
14
13
  end
15
14
 
16
- def self.failure_action=(env)
17
- @@failure_action = env
15
+ def failure_action
16
+ @failure_action ||= 'retry'
18
17
  end
19
18
 
20
-
21
- def self.table_name
22
- "#{self.queue_prefix}boss_queue_jobs"
19
+ def table_name
20
+ "#{BossQueue.queue_prefix}boss_queue_jobs"
23
21
  end
24
22
 
25
- def self.queue_name
26
- "#{self.queue_prefix}boss_queue"
23
+ def queue_name
24
+ "#{BossQueue.queue_prefix}boss_queue#{@queue_postfix}"
27
25
  end
28
26
 
29
27
 
30
- def self.create_table(read_capacity=1, write_capacity=1, options={})
28
+ def create_table(read_capacity=1, write_capacity=1, options={})
31
29
  create_opts = {}
32
30
  create_opts[:hash_key] = { :id => :string }
33
31
 
34
- AWS::DynamoDB.new.tables.create(self.table_name, read_capacity, write_capacity, create_opts)
32
+ AWS::DynamoDB.new.tables.create(table_name, read_capacity, write_capacity, create_opts)
35
33
  end
36
34
 
37
- def self.create_queue
38
- AWS::SQS::QueueCollection.new.create(self.queue_name, :default_visibility_timeout => 5 * 60)
35
+ def create_queue
36
+ AWS::SQS::QueueCollection.new.create(queue_name, :default_visibility_timeout => 5 * 60)
39
37
  end
40
38
 
41
- def self.work
39
+ def work
42
40
  work_done = false
43
- self.sqs_queue.receive_message do |job_id|
41
+ sqs_queue.receive_message do |job_id|
44
42
  # When a block is given, each message is yielded to the block and then deleted as long as the block exits normally - http://docs.aws.amazon.com/AWSRubySDK/latest/frames.html
45
43
  begin
46
44
  job = BossQueue::Job.shard(table_name).find(job_id.body)
47
- job.queue_name = self.queue_name
45
+ job.sqs_queue = sqs_queue
48
46
  job.work
49
47
  work_done = true
50
48
  rescue AWS::Record::RecordNotFound
@@ -53,17 +51,17 @@ class BossQueue
53
51
  work_done
54
52
  end
55
53
 
56
- def self.enqueue(class_or_instance, method_name, *args)
57
- job = self.create_job(class_or_instance, method_name, *args)
54
+ def enqueue(class_or_instance, method_name, *args)
55
+ job = create_job(class_or_instance, method_name, *args)
58
56
  job.enqueue
59
57
  end
60
58
 
61
- def self.enqueue_with_delay(delay, class_or_instance, method_name, *args)
62
- job = self.create_job(class_or_instance, method_name, *args)
59
+ def enqueue_with_delay(delay, class_or_instance, method_name, *args)
60
+ job = create_job(class_or_instance, method_name, *args)
63
61
  job.enqueue_with_delay(delay)
64
62
  end
65
63
 
66
- def self.create_job(class_or_instance, method_name, *args) # :nodoc:
64
+ def create_job(class_or_instance, method_name, *args) # :nodoc:
67
65
  job = BossQueue::Job.shard(table_name).new
68
66
  if class_or_instance.is_a?(Class)
69
67
  class_name = class_or_instance.to_s
@@ -74,8 +72,8 @@ class BossQueue
74
72
  instance_id = class_or_instance.id
75
73
  job.kind = "#{class_name}##{method_name}"
76
74
  end
77
- job.queue_name = self.queue_name
78
- job.failure_action = self.failure_action
75
+ job.queue_name = queue_name
76
+ job.failure_action = failure_action
79
77
  job.model_class_name = class_name
80
78
  job.model_id = instance_id unless instance_id.nil?
81
79
  job.job_method = method_name.to_s
@@ -84,8 +82,8 @@ class BossQueue
84
82
  job
85
83
  end
86
84
 
87
- def self.sqs_queue # :nodoc:
88
- AWS::SQS.new.queues[AWS::SQS.new.queues.url_for(self.queue_name)]
85
+ def sqs_queue # :nodoc:
86
+ @sqs_queue ||= AWS::SQS.new.queues[AWS::SQS.new.queues.url_for(queue_name)]
89
87
  end
90
88
 
91
89
  def self.environment # :nodoc:
@@ -66,10 +66,14 @@ class BossQueue
66
66
  60 * 2**(failed_attempts - 1)
67
67
  end
68
68
 
69
+ def sqs_queue=(queue_obj) # :nodoc:
70
+ @sqs_queue = queue_obj
71
+ end
72
+
69
73
  private
70
74
 
71
75
  def sqs_queue
72
- AWS::SQS.new.queues[AWS::SQS.new.queues.url_for(queue_name)]
76
+ @sqs_queue ||= AWS::SQS.new.queues[AWS::SQS.new.queues.url_for(queue_name)]
73
77
  end
74
78
 
75
79
  # from ActiveSupport source: http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-constantize
@@ -1,6 +1,19 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
3
  describe "BossQueue module" do
4
+ before(:each) do
5
+ BossQueue.environment = 'test'
6
+
7
+ BossQueue::Job.any_instance.stub(:kind=)
8
+ BossQueue::Job.any_instance.stub(:queue_name=)
9
+ BossQueue::Job.any_instance.stub(:failure_action=)
10
+ BossQueue::Job.any_instance.stub(:model_class_name=)
11
+ BossQueue::Job.any_instance.stub(:model_id=)
12
+ BossQueue::Job.any_instance.stub(:job_method=)
13
+ BossQueue::Job.any_instance.stub(:job_arguments=)
14
+ BossQueue::Job.any_instance.stub(:save!)
15
+ BossQueue::Job.any_instance.stub(:enqueue)
16
+ end
4
17
 
5
18
  it "should respond to environment" do
6
19
  BossQueue.should respond_to(:environment)
@@ -10,17 +23,13 @@ describe "BossQueue module" do
10
23
  BossQueue.should respond_to(:environment=)
11
24
  end
12
25
 
13
- it "should respond to failure_action" do
14
- BossQueue.should respond_to(:failure_action)
15
- end
16
-
17
- it "should respond to failure_action=" do
18
- BossQueue.should respond_to(:failure_action=)
19
- end
20
-
21
26
  describe "#failure_action" do
22
27
  it "should default to 'retry'" do
23
- BossQueue.failure_action.should == 'retry'
28
+ BossQueue.new.failure_action.should == 'retry'
29
+ end
30
+
31
+ it "should be overridable by a :failure_action option on initialize" do
32
+ BossQueue.new(:failure_action => 'none').failure_action.should == 'none'
24
33
  end
25
34
  end
26
35
 
@@ -32,35 +41,35 @@ describe "BossQueue module" do
32
41
  context "when @@environment is 'development'" do
33
42
  it "should be 'dev_boss_queue_jobs'" do
34
43
  BossQueue.environment = 'development'
35
- BossQueue.table_name.should == 'dev_boss_queue_jobs'
44
+ BossQueue.new.table_name.should == 'dev_boss_queue_jobs'
36
45
  end
37
46
  end
38
47
 
39
48
  context "when @@environment is 'production'" do
40
49
  it "should be 'boss_queue_jobs'" do
41
50
  BossQueue.environment = 'production'
42
- BossQueue.table_name.should == 'boss_queue_jobs'
51
+ BossQueue.new.table_name.should == 'boss_queue_jobs'
43
52
  end
44
53
  end
45
54
 
46
55
  context "when @@environment is 'staging'" do
47
56
  it "should be 'staging_boss_queue_jobs'" do
48
57
  BossQueue.environment = 'staging'
49
- BossQueue.table_name.should == 'staging_boss_queue_jobs'
58
+ BossQueue.new.table_name.should == 'staging_boss_queue_jobs'
50
59
  end
51
60
  end
52
61
 
53
62
  context "when @@environment is 'staging'" do
54
63
  it "should be 'staging_boss_queue_jobs'" do
55
64
  BossQueue.environment = 'staging'
56
- BossQueue.table_name.should == 'staging_boss_queue_jobs'
65
+ BossQueue.new.table_name.should == 'staging_boss_queue_jobs'
57
66
  end
58
67
  end
59
68
 
60
69
  context "when @@environment is nil" do
61
70
  it "should raise an exception" do
62
71
  lambda {
63
- BossQueue.table_name
72
+ BossQueue.new.table_name
64
73
  }.should raise_error
65
74
  end
66
75
  end
@@ -75,38 +84,45 @@ describe "BossQueue module" do
75
84
  context "when @@environment is 'development'" do
76
85
  it "should be 'dev_boss_queue'" do
77
86
  BossQueue.environment = 'development'
78
- BossQueue.queue_name.should == 'dev_boss_queue'
87
+ BossQueue.new.queue_name.should == 'dev_boss_queue'
79
88
  end
80
89
  end
81
90
 
82
91
  context "when @@environment is 'production'" do
83
92
  it "should be 'boss_queue'" do
84
93
  BossQueue.environment = 'production'
85
- BossQueue.queue_name.should == 'boss_queue'
94
+ BossQueue.new.queue_name.should == 'boss_queue'
86
95
  end
87
96
  end
88
97
 
89
98
  context "when @@environment is 'staging'" do
90
99
  it "should be 'staging_boss_queue'" do
91
100
  BossQueue.environment = 'staging'
92
- BossQueue.queue_name.should == 'staging_boss_queue'
101
+ BossQueue.new.queue_name.should == 'staging_boss_queue'
93
102
  end
94
103
  end
95
104
 
96
105
  context "when @@environment is 'staging'" do
97
106
  it "should be 'staging_boss_queue'" do
98
107
  BossQueue.environment = 'staging'
99
- BossQueue.queue_name.should == 'staging_boss_queue'
108
+ BossQueue.new.queue_name.should == 'staging_boss_queue'
100
109
  end
101
110
  end
102
111
 
103
112
  context "when @@environment is nil" do
104
113
  it "should raise an exception" do
105
114
  lambda {
106
- BossQueue.queue_name
115
+ BossQueue.new.queue_name
107
116
  }.should raise_error
108
117
  end
109
118
  end
119
+
120
+ context "when a queue option is included in the initializer" do
121
+ it "should append that to the queue name" do
122
+ BossQueue.environment = 'production'
123
+ BossQueue.new(:queue => 'emails').queue_name.should == 'boss_queue_emails'
124
+ end
125
+ end
110
126
  end
111
127
 
112
128
  describe "#enqueue" do
@@ -129,8 +145,7 @@ describe "BossQueue module" do
129
145
 
130
146
  context "when a class" do
131
147
  it "should initialize a new BossQueue::Job object, save and call enqueue on it" do
132
- BossQueue.environment = 'test'
133
- BossQueue.failure_action = 'retry'
148
+ queue = BossQueue.new
134
149
  BossQueue::Job.any_instance.should_receive(:kind=).with('TestClass@test_class_method')
135
150
  BossQueue::Job.any_instance.should_receive(:queue_name=).with('test_boss_queue')
136
151
  BossQueue::Job.any_instance.should_receive(:failure_action=).with('retry')
@@ -140,14 +155,13 @@ describe "BossQueue module" do
140
155
  BossQueue::Job.any_instance.should_receive(:job_arguments=).with(@argument_json)
141
156
  BossQueue::Job.any_instance.should_receive(:save!)
142
157
  BossQueue::Job.any_instance.should_receive(:enqueue)
143
- BossQueue.enqueue(TestClass, :test_class_method, 'a', 'b', { 'c' => 2, 'd' => 1 })
158
+ queue.enqueue(TestClass, :test_class_method, 'a', 'b', { 'c' => 2, 'd' => 1 })
144
159
  end
145
160
  end
146
161
 
147
162
  context "when a class instance" do
148
163
  it "should initialize a new BossQueue::Job object, save and call enqueue on it" do
149
- BossQueue.environment = 'test'
150
- BossQueue.failure_action = 'retry'
164
+ queue = BossQueue.new
151
165
  BossQueue::Job.any_instance.should_receive(:kind=).with('TestClass#test_instance_method')
152
166
  BossQueue::Job.any_instance.should_receive(:queue_name=).with('test_boss_queue')
153
167
  BossQueue::Job.any_instance.should_receive(:failure_action=).with('retry')
@@ -157,7 +171,7 @@ describe "BossQueue module" do
157
171
  BossQueue::Job.any_instance.should_receive(:job_arguments=).with(@argument_json)
158
172
  BossQueue::Job.any_instance.should_receive(:save!)
159
173
  BossQueue::Job.any_instance.should_receive(:enqueue)
160
- BossQueue.enqueue(TestClass.new, :test_instance_method, 'a', 'b', { 'c' => 2, 'd' => 1 })
174
+ queue.enqueue(TestClass.new, :test_instance_method, 'a', 'b', { 'c' => 2, 'd' => 1 })
161
175
  end
162
176
  end
163
177
 
@@ -171,8 +185,7 @@ describe "BossQueue module" do
171
185
 
172
186
  context "when a class" do
173
187
  it "should initialize a new BossQueue::Job object, save and call enqueue on it" do
174
- BossQueue.environment = 'test'
175
- BossQueue.failure_action = 'retry'
188
+ queue = BossQueue.new
176
189
  BossQueue::Job.any_instance.should_receive(:kind=).with('TestClass@test_class_method')
177
190
  BossQueue::Job.any_instance.should_receive(:queue_name=).with('test_boss_queue')
178
191
  BossQueue::Job.any_instance.should_receive(:failure_action=).with('retry')
@@ -182,14 +195,13 @@ describe "BossQueue module" do
182
195
  BossQueue::Job.any_instance.should_receive(:job_arguments=).with(@argument_json)
183
196
  BossQueue::Job.any_instance.should_receive(:save!)
184
197
  BossQueue::Job.any_instance.should_receive(:enqueue_with_delay).with(60)
185
- BossQueue.enqueue_with_delay(60, TestClass, :test_class_method, 'a', 'b', { 'c' => 2, 'd' => 1 })
198
+ queue.enqueue_with_delay(60, TestClass, :test_class_method, 'a', 'b', { 'c' => 2, 'd' => 1 })
186
199
  end
187
200
  end
188
201
 
189
202
  context "when a class instance" do
190
203
  it "should initialize a new BossQueue::Job object, save and call enqueue on it" do
191
- BossQueue.environment = 'test'
192
- BossQueue.failure_action = 'retry'
204
+ queue = BossQueue.new
193
205
  BossQueue::Job.any_instance.should_receive(:kind=).with('TestClass#test_instance_method')
194
206
  BossQueue::Job.any_instance.should_receive(:queue_name=).with('test_boss_queue')
195
207
  BossQueue::Job.any_instance.should_receive(:failure_action=).with('retry')
@@ -199,7 +211,7 @@ describe "BossQueue module" do
199
211
  BossQueue::Job.any_instance.should_receive(:job_arguments=).with(@argument_json)
200
212
  BossQueue::Job.any_instance.should_receive(:save!)
201
213
  BossQueue::Job.any_instance.should_receive(:enqueue_with_delay).with(60)
202
- BossQueue.enqueue_with_delay(60, TestClass.new, :test_instance_method, 'a', 'b', { 'c' => 2, 'd' => 1 })
214
+ queue.enqueue_with_delay(60, TestClass.new, :test_instance_method, 'a', 'b', { 'c' => 2, 'd' => 1 })
203
215
  end
204
216
  end
205
217
 
@@ -207,59 +219,64 @@ describe "BossQueue module" do
207
219
 
208
220
  describe "#work" do
209
221
  before(:each) do
210
- @queue = double('queue')
222
+ @sqs_queue = double('queue')
211
223
  AWS::SQS.stub_chain(:new, :queues, :url_for).and_return('queue_url')
212
- AWS::SQS.stub_chain(:new, :queues, :[]).and_return(@queue)
224
+ AWS::SQS.stub_chain(:new, :queues, :[]).and_return(@sqs_queue)
213
225
 
214
226
  @sqs_message = double('message')
215
227
  @sqs_message.stub(:body).and_return('ijk')
216
- @queue.stub(:receive_message)
228
+ @sqs_queue.stub(:receive_message)
217
229
 
218
230
  @job = double('job')
219
231
  @job.stub(:work)
220
- @job.stub(:queue_name=)
232
+ @job.stub(:sqs_queue=)
221
233
  BossQueue::Job.stub_chain(:shard, :find).and_return(@job)
222
234
  end
223
235
 
224
- it "should dequeue from SQS" do
225
- @queue.should_receive(:receive_message).and_yield(@sqs_message)
226
- BossQueue.work
236
+ it "should dequeue from SQS using the value of sqs_queue_url" do
237
+ @sqs_queue.should_receive(:receive_message).and_yield(@sqs_message)
238
+ BossQueue.new.work
227
239
  end
228
240
 
229
241
  context "when something is dequeued from SQS" do
230
242
  before(:each) do
231
- @queue.should_receive(:receive_message).and_yield(@sqs_message)
243
+ @sqs_queue.should_receive(:receive_message).and_yield(@sqs_message)
232
244
  end
233
245
 
234
246
  it "should use the dequeued id to retrieve a BossQueue::Job object" do
235
247
  shard = double('shard')
236
- BossQueue::Job.should_receive(:shard).with(BossQueue.table_name).and_return(shard)
248
+ BossQueue::Job.should_receive(:shard).with(BossQueue.new.table_name).and_return(shard)
237
249
  shard.should_receive(:find).with('ijk').and_return(@job)
238
- BossQueue.work
250
+ BossQueue.new.work
239
251
  end
240
252
 
241
253
  context "when the dequeued id does not match a BossQueue::Job object" do
242
254
  it "should not raise an exception" do
243
255
  BossQueue::Job.stub_chain(:shard, :find).and_raise(AWS::Record::RecordNotFound.new)
244
256
  lambda {
245
- BossQueue.work
257
+ BossQueue.new.work
246
258
  }.should_not raise_error
247
259
  end
248
260
  end
249
261
 
262
+ it "should set the sqs_queue of the job since we already did the work of retrieving it's url" do
263
+ @job.should_receive(:sqs_queue=).with(@sqs_queue)
264
+ BossQueue.new.work
265
+ end
266
+
250
267
  it "should call work on the BossQueue::Job object" do
251
268
  @job.should_receive(:work)
252
- BossQueue.work
269
+ BossQueue.new.work
253
270
  end
254
271
 
255
272
  it "should return true" do
256
- BossQueue.work.should be_true
273
+ BossQueue.new.work.should be_true
257
274
  end
258
275
  end
259
276
 
260
277
  context "when nothing is dequeued from SQS" do
261
278
  it "should return false" do
262
- BossQueue.work.should be_false
279
+ BossQueue.new.work.should be_false
263
280
  end
264
281
  end
265
282
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: boss_queue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.10
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -160,7 +160,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
160
160
  version: '0'
161
161
  segments:
162
162
  - 0
163
- hash: -2976249042738102520
163
+ hash: 539574413423499853
164
164
  required_rubygems_version: !ruby/object:Gem::Requirement
165
165
  none: false
166
166
  requirements: