super_queue 0.1.1 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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