super_queue 0.1.1 → 0.2.1

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 (2) hide show
  1. data/lib/super_queue.rb +74 -109
  2. metadata +4 -4
data/lib/super_queue.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'fog'
1
+ require 'aws-sdk'
2
2
  require 'base64'
3
3
  require 'socket'
4
4
  require 'digest/md5'
@@ -6,20 +6,11 @@ require 'zlib'
6
6
 
7
7
  class SuperQueue
8
8
 
9
- def self.mock!
10
- @@mock = true
11
- Fog.mock!
12
- end
13
-
14
- def self.mocking?
15
- defined?(@@mock) && @@mock
16
- end
17
-
18
9
  def initialize(opts)
10
+ AWS.eager_autoload! # for thread safety
19
11
  check_opts(opts)
20
- opts[:localize_queue] = true unless opts.has_key? :localized_queue
12
+ @should_poll_sqs = opts[:should_poll_sqs]
21
13
  @buffer_size = opts[:buffer_size] || 100
22
- @localize_queue = opts[:localize_queue]
23
14
  @queue_name = generate_queue_name(opts)
24
15
  @request_count = 0
25
16
  initialize_sqs(opts)
@@ -31,12 +22,11 @@ class SuperQueue
31
22
  @in_buffer = []
32
23
  @out_buffer = []
33
24
  @deletion_queue = []
34
- @mock_length = 0 if SuperQueue.mocking?
35
25
 
36
26
  @compressor = Zlib::Deflate.new
37
27
  @decompressor = Zlib::Inflate.new
38
28
 
39
- @sqs_tracker = Thread.new { poll_sqs }
29
+ @sqs_tracker = Thread.new { poll_sqs } if @should_poll_sqs
40
30
  @gc = Thread.new { collect_garbage }
41
31
  end
42
32
 
@@ -94,14 +84,14 @@ class SuperQueue
94
84
  end
95
85
 
96
86
  def shutdown
97
- @sqs_tracker.terminate
87
+ @sqs_tracker.terminate if @should_poll_sqs
98
88
  @mutex.synchronize { clear_in_buffer }
99
89
  @gc.terminate
100
90
  @mutex.synchronize { clear_deletion_queue }
101
91
  end
102
92
 
103
93
  def destroy
104
- @sqs_tracker.terminate
94
+ @sqs_tracker.terminate if @should_poll_sqs
105
95
  @gc.terminate
106
96
  delete_queue
107
97
  end
@@ -126,10 +116,6 @@ class SuperQueue
126
116
  queue_name
127
117
  end
128
118
 
129
- def localized?
130
- !!@localize_queue
131
- end
132
-
133
119
  private
134
120
 
135
121
  #
@@ -148,11 +134,11 @@ class SuperQueue
148
134
 
149
135
  def create_sqs_connection(opts)
150
136
  aws_options = {
151
- :aws_access_key_id => opts[:aws_access_key_id],
152
- :aws_secret_access_key => opts[:aws_secret_access_key]
137
+ :access_key_id => opts[:aws_access_key_id],
138
+ :secret_access_key => opts[:aws_secret_access_key]
153
139
  }
154
140
  begin
155
- @sqs = Fog::AWS::SQS.new(aws_options)
141
+ @sqs = AWS::SQS.new(aws_options)
156
142
  rescue Exception => e
157
143
  raise e
158
144
  end
@@ -161,20 +147,29 @@ class SuperQueue
161
147
  def create_sqs_queue(opts)
162
148
  retries = 0
163
149
  begin
164
- @sqs_queue = new_sqs_queue(opts)
150
+ @sqs_queue = find_queue_by_name || new_sqs_queue(opts)
165
151
  check_for_queue_creation_success
166
152
  rescue RuntimeError => e
167
153
  retries += 1
168
- (retries >= 10) ? retry : raise(e)
154
+ sleep 1
155
+ (retries >= 20) ? retry : raise(e)
156
+ end
157
+ end
158
+
159
+ def find_queue_by_name
160
+ begin
161
+ @sqs.queues.named(queue_name)
162
+ rescue AWS::SQS::Errors::NonExistentQueue
163
+ return nil
169
164
  end
170
165
  end
171
166
 
172
167
  def new_sqs_queue(opts)
173
168
  @request_count += 1
174
169
  if opts[:visibility_timeout]
175
- @sqs.create_queue(queue_name, {"DefaultVisibilityTimeout" => opts[:visibility_timeout]})
170
+ @sqs.queues.create(queue_name, { :visibility_timeout => opts[:visibility_timeout] })
176
171
  else
177
- @sqs.create_queue(queue_name)
172
+ @sqs.queues.create(queue_name)
178
173
  end
179
174
  end
180
175
 
@@ -187,56 +182,59 @@ class SuperQueue
187
182
  raise "Couldn't create queue #{queue_name}, or delete existing queue by this name." if q_url.nil?
188
183
  end
189
184
 
190
- def send_message_to_queue
191
- p = @in_buffer.shift
192
- payload = is_a_link?(p) ? p : encode(p)
193
- retries = 0
194
- begin
185
+ def send_messages_to_queue
186
+ number_of_batches = @in_buffer.size / 10
187
+ number_of_batches += 1 if @in_buffer.size % 10
188
+ batches = []
189
+ number_of_batches.times do
190
+ batch = []
191
+ 10.times do
192
+ p = @in_buffer.shift
193
+ obj = is_a_link?(p) ? p : encode(p)
194
+ batch << obj
195
+ end
196
+ batches << batch
197
+ end
198
+
199
+ #Ugliness! But I'm not sure how else to tackle this at the moment
200
+ batches.each do |b|
195
201
  @request_count += 1
196
- @sqs.send_message(q_url, payload)
197
- rescue Excon::Errors::BadRequest => e
198
- retries += 1
199
- (retries >= 10) ? retry : raise(e)
202
+ @sqs_queue.batch_send(b)
200
203
  end
201
- @mock_length += 1 if SuperQueue.mocking?
202
204
  end
203
205
 
204
- def get_message_from_queue
205
- message = @sqs.receive_message(q_url)
206
- return nil if message.body.nil? || message.body['Message'].first.nil?
207
- handle = message.body['Message'].first['ReceiptHandle']
208
- ser_obj = message.body['Message'].first['Body']
209
- return nil if ser_obj.nil? || ser_obj.empty?
210
- @mock_length -= 1 if SuperQueue.mocking?
211
- @request_count += 1
212
- return {:handle => handle, :payload => ser_obj} if is_a_link?(ser_obj)
213
- { :handle => handle, :payload => decode(ser_obj) }
206
+ def get_messages_from_queue(number_of_messages_to_receive)
207
+ messages = []
208
+ number_of_batches = number_of_messages_to_receive / 10
209
+ number_of_batches += 1 if number_of_messages_to_receive % 10
210
+ number_of_batches.times do |c|
211
+ batch = @sqs_queue.receive_messages(:limit => 10)
212
+ batch.each do |m|
213
+ if is_a_link?(m.body)
214
+ obj = {:message => m, :payload => m.body}
215
+ else
216
+ obj = { :message => m, :payload => decode(m.body) }
217
+ end
218
+ messages << obj
219
+ end
220
+ @request_count += 1
221
+ end
222
+ messages
214
223
  end
215
224
 
216
225
  def sqs_length
217
- return @mock_length if SuperQueue.mocking?
218
- body = @sqs.get_queue_attributes(q_url, "ApproximateNumberOfMessages").body
219
- @request_count += 1
220
- begin
221
- retval = 0
222
- if body
223
- attrs = body["Attributes"]
224
- if attrs
225
- retval = attrs["ApproximateNumberOfMessages"]
226
- end
227
- end
228
- end until !retval.nil?
229
- retval
226
+ n = @sqs_queue.approximate_number_of_messages
227
+ return n.is_a?(Integer) ? n : 0
230
228
  end
231
229
 
232
230
  def delete_queue
233
231
  @request_count += 1
234
- @sqs.delete_queue(q_url)
232
+ @sqs_queue.delete
235
233
  end
236
234
 
237
235
  def clear_deletion_queue
238
236
  while !@deletion_queue.empty?
239
- @sqs.delete_message(q_url, @deletion_queue.shift)
237
+ @sqs_queue.batch_delete(@deletion_queue[0..9])
240
238
  @request_count += 1
241
239
  end
242
240
  end
@@ -247,15 +245,9 @@ class SuperQueue
247
245
  def fill_out_buffer_from_sqs_queue
248
246
  return false if sqs_length == 0
249
247
  @gc.wakeup if @gc.stop? # This is the best time to do GC, because there are no pops happening.
250
- nil_count = 0
251
- while (@out_buffer.size < @buffer_size) && (nil_count < 5) # If you get nil 5 times in a row, SQS is probably empty
252
- m = get_message_from_queue
253
- if m.nil?
254
- nil_count += 1
255
- else
256
- @out_buffer.push m
257
- nil_count = 0
258
- end
248
+ while (@out_buffer.size < @buffer_size)
249
+ messages = get_messages_from_queue(@buffer_size - @out_buffer.size)
250
+ messages.each { |m| @out_buffer.push m }
259
251
  end
260
252
  !@out_buffer.empty?
261
253
  end
@@ -270,13 +262,13 @@ class SuperQueue
270
262
 
271
263
  def pop_out_buffer
272
264
  m = @out_buffer.shift
273
- @deletion_queue << m[:handle] if m[:handle]
265
+ @deletion_queue << m[:message] if m[:message]
274
266
  m[:payload]
275
267
  end
276
268
 
277
269
  def clear_in_buffer
278
270
  while !@in_buffer.empty? do
279
- send_message_to_queue
271
+ send_messages_to_queue
280
272
  end
281
273
  end
282
274
 
@@ -291,24 +283,16 @@ class SuperQueue
291
283
  # Misc helper methods
292
284
  #
293
285
  def encode(p)
294
- text = Base64.encode64(Marshal.dump(p))
295
- retval = nil
296
- retries = 0
297
- begin
298
- retval = @compressor.deflate(text)
299
- retries += 1
300
- end until !(retval.nil? || retval.empty?) || (retries > 5)
301
- retval
286
+ Base64.urlsafe_encode64(Marshal.dump(p))
302
287
  end
303
288
 
304
289
  def decode(ser_obj)
305
- text = nil
306
- retries = 0
307
- begin
308
- text = @decompressor.inflate(ser_obj)
309
- retries += 1
310
- end until !(text.nil? || text.empty?) || (retries > 5)
311
- Marshal.load(Base64.decode64(text))
290
+ #puts "Decode: Decoding message #{ser_obj} from base64..."
291
+ obj = Base64.urlsafe_decode64(ser_obj)
292
+ #puts "Decode: Object decoded as #{obj}. Doing Marshal load..."
293
+ ret = Marshal.load(obj)
294
+ #puts "Decode: Marshal loaded as #{ret}"
295
+ ret
312
296
  end
313
297
 
314
298
  def is_a_link?(s)
@@ -318,15 +302,7 @@ class SuperQueue
318
302
 
319
303
  def generate_queue_name(opts)
320
304
  q_name = opts[:name] || random_name
321
- if opts[:namespace] && opts[:localize_queue]
322
- "#{@namespace}-#{Digest::MD5.hexdigest(local_ip)}-#{q_name}"
323
- elsif opts[:namespace]
324
- "#{@namespace}-#{q_name}"
325
- elsif opts[:localize_queue]
326
- "#{Digest::MD5.hexdigest(local_ip)}-#{q_name}"
327
- else
328
- q_name
329
- end
305
+ return opts[:namespace] ? "#{@namespace}-#{q_name}" : q_name
330
306
  end
331
307
 
332
308
  #
@@ -334,7 +310,7 @@ class SuperQueue
334
310
  #
335
311
  def q_url
336
312
  return @q_url if @q_url
337
- @q_url = @sqs_queue.body['QueueUrl']
313
+ @q_url = @sqs_queue.url
338
314
  @q_url
339
315
  end
340
316
 
@@ -347,17 +323,6 @@ class SuperQueue
347
323
  @queue_name
348
324
  end
349
325
 
350
- def local_ip
351
- orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true # turn off reverse DNS resolution temporarily
352
- return "127.0.0.1" if SuperQueue.mocking?
353
- UDPSocket.open do |s|
354
- s.connect '64.233.187 .99', 1
355
- s.addr.last
356
- end
357
- ensure
358
- Socket.do_not_reverse_lookup = orig
359
- end
360
-
361
326
  #
362
327
  # Maintence thread-related methods
363
328
  #
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: super_queue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -12,18 +12,18 @@ cert_chain: []
12
12
  date: 2013-02-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: fog
15
+ name: aws-sdk
16
16
  version_requirements: !ruby/object:Gem::Requirement
17
17
  requirements:
18
18
  - - ~>
19
19
  - !ruby/object:Gem::Version
20
- version: 1.9.0
20
+ version: 1.6.5
21
21
  none: false
22
22
  requirement: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ~>
25
25
  - !ruby/object:Gem::Version
26
- version: 1.9.0
26
+ version: 1.6.5
27
27
  none: false
28
28
  prerelease: false
29
29
  type: :runtime