super_queue 0.0.9 → 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.
Files changed (2) hide show
  1. data/lib/super_queue.rb +123 -72
  2. metadata +2 -2
data/lib/super_queue.rb CHANGED
@@ -2,6 +2,7 @@ require 'fog'
2
2
  require 'base64'
3
3
  require 'socket'
4
4
  require 'digest/md5'
5
+ require 'zlib'
5
6
 
6
7
  class SuperQueue
7
8
 
@@ -20,6 +21,7 @@ class SuperQueue
20
21
  @buffer_size = opts[:buffer_size] || 100
21
22
  @localize_queue = opts[:localize_queue]
22
23
  @queue_name = generate_queue_name(opts)
24
+ @request_count = 0
23
25
  initialize_sqs(opts)
24
26
 
25
27
  @waiting = []
@@ -31,6 +33,9 @@ class SuperQueue
31
33
  @deletion_queue = []
32
34
  @mock_length = 0 if SuperQueue.mocking?
33
35
 
36
+ @compressor = Zlib::Deflate.new
37
+ @decompressor = Zlib::Inflate.new
38
+
34
39
  @sqs_tracker = Thread.new { poll_sqs }
35
40
  @gc = Thread.new { collect_garbage }
36
41
  end
@@ -101,6 +106,10 @@ class SuperQueue
101
106
  delete_queue
102
107
  end
103
108
 
109
+ def sqs_requests
110
+ @request_count
111
+ end
112
+
104
113
  alias enq push
105
114
  alias << push
106
115
 
@@ -123,34 +132,15 @@ class SuperQueue
123
132
 
124
133
  private
125
134
 
126
- def poll_sqs
127
- loop do
128
- @mutex.synchronize { fill_out_buffer_from_sqs_queue || fill_out_buffer_from_in_buffer } if @out_buffer.empty?
129
- @mutex.synchronize { clear_in_buffer } if !@in_buffer.empty? && (@in_buffer.size > @buffer_size)
130
- Thread.pass
131
- end
132
- end
133
-
134
- def collect_garbage
135
- loop do
136
- #This also needs a condition to clear the del queue if there are any handles where the invisibility is about to expire
137
- @mutex.synchronize { clear_deletion_queue } if !@deletion_queue.empty? && (@deletion_queue.size >= (@buffer_size / 2))
138
- sleep
139
- end
140
- end
141
-
142
- def check_opts(opts)
143
- raise "Options can't be nil!" if opts.nil?
144
- raise "Minimun :buffer_size is 5." if opts[:buffer_size] && (opts[:buffer_size] < 5)
145
- raise "AWS credentials :aws_access_key_id and :aws_secret_access_key required!" unless opts[:aws_access_key_id] && opts[:aws_secret_access_key]
146
- raise "Visbility timeout must be an integer (in seconds)!" if opts[:visibility_timeout] && !opts[:visibility_timeout].is_a?(Integer)
147
- end
148
-
135
+ #
136
+ # Amazon SQS methods
137
+ #
149
138
  def initialize_sqs(opts)
150
139
  create_sqs_connection(opts)
151
140
  create_sqs_queue(opts)
152
141
  check_for_queue_creation_success
153
142
  @sqs.set_queue_attributes(q_url, "VisibilityTimeout", opts[:visibility_timeout]) if opts[:visibility_timeout]
143
+ @request_count += 1
154
144
  end
155
145
 
156
146
  def create_sqs_connection(opts)
@@ -177,6 +167,7 @@ class SuperQueue
177
167
  @sqs_queue = @sqs.create_queue(queue_name)
178
168
  end
179
169
  end
170
+ @request_count += 1
180
171
  end
181
172
 
182
173
  def check_for_queue_creation_success
@@ -190,9 +181,10 @@ class SuperQueue
190
181
 
191
182
  def send_message_to_queue
192
183
  p = @in_buffer.shift
193
- payload = is_a_link?(p) ? p : Base64.encode64(Marshal.dump(p))
184
+ payload = is_a_link?(p) ? p : encode(p)
194
185
  @sqs.send_message(q_url, payload)
195
186
  @mock_length += 1 if SuperQueue.mocking?
187
+ @request_count += 1
196
188
  end
197
189
 
198
190
  def get_message_from_queue
@@ -202,46 +194,15 @@ class SuperQueue
202
194
  ser_obj = message.body['Message'].first['Body']
203
195
  return nil if ser_obj.nil? || ser_obj.empty?
204
196
  @mock_length -= 1 if SuperQueue.mocking?
197
+ @request_count += 1
205
198
  return {:handle => handle, :payload => ser_obj} if is_a_link?(ser_obj)
206
- { :handle => handle, :payload => Marshal.load(Base64.decode64(ser_obj)) }
207
- end
208
-
209
- def q_url
210
- return @q_url if @q_url
211
- @q_url = @sqs_queue.body['QueueUrl']
212
- @q_url
213
- end
214
-
215
- def is_a_link?(s)
216
- return false unless s.is_a? String
217
- (s[0..6] == "http://") || (s[0..7] == "https://")
218
- end
219
-
220
- def delete_queue
221
- @sqs.delete_queue(q_url)
222
- end
223
-
224
- def generate_queue_name(opts)
225
- q_name = opts[:name] || random_name
226
- if opts[:namespace] && opts[:localize_queue]
227
- "#{@namespace}-#{Digest::MD5.hexdigest(local_ip)}-#{q_name}"
228
- elsif opts[:namespace]
229
- "#{@namespace}-#{q_name}"
230
- elsif opts[:localize_queue]
231
- "#{Digest::MD5.hexdigest(local_ip)}-#{q_name}"
232
- else
233
- q_name
234
- end
235
- end
236
-
237
- def random_name
238
- o = [('a'..'z'),('A'..'Z')].map{|i| i.to_a}.flatten
239
- (0...15).map{ o[rand(o.length)] }.join
199
+ { :handle => handle, :payload => decode(ser_obj) }
240
200
  end
241
201
 
242
202
  def sqs_length
243
203
  return @mock_length if SuperQueue.mocking?
244
204
  body = @sqs.get_queue_attributes(q_url, "ApproximateNumberOfMessages").body
205
+ @request_count += 1
245
206
  begin
246
207
  retval = 0
247
208
  if body
@@ -254,17 +215,21 @@ class SuperQueue
254
215
  retval
255
216
  end
256
217
 
257
- def local_ip
258
- orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true # turn off reverse DNS resolution temporarily
259
- return "127.0.0.1" if SuperQueue.mocking?
260
- UDPSocket.open do |s|
261
- s.connect '64.233.187 .99', 1
262
- s.addr.last
218
+ def delete_queue
219
+ @request_count += 1
220
+ @sqs.delete_queue(q_url)
221
+ end
222
+
223
+ def clear_deletion_queue
224
+ while !@deletion_queue.empty?
225
+ @sqs.delete_message(q_url, @deletion_queue.shift)
226
+ @request_count += 1
263
227
  end
264
- ensure
265
- Socket.do_not_reverse_lookup = orig
266
228
  end
267
229
 
230
+ #
231
+ # Buffer-related methods
232
+ #
268
233
  def fill_out_buffer_from_sqs_queue
269
234
  return false if sqs_length == 0
270
235
  @gc.wakeup if @gc.stop? # This is the best time to do GC, because there are no pops happening.
@@ -295,20 +260,106 @@ class SuperQueue
295
260
  m[:payload]
296
261
  end
297
262
 
263
+ def clear_in_buffer
264
+ while !@in_buffer.empty? do
265
+ send_message_to_queue
266
+ end
267
+ end
268
+
269
+ def check_opts(opts)
270
+ raise "Options can't be nil!" if opts.nil?
271
+ raise "Minimun :buffer_size is 5." if opts[:buffer_size] && (opts[:buffer_size] < 5)
272
+ raise "AWS credentials :aws_access_key_id and :aws_secret_access_key required!" unless opts[:aws_access_key_id] && opts[:aws_secret_access_key]
273
+ raise "Visbility timeout must be an integer (in seconds)!" if opts[:visibility_timeout] && !opts[:visibility_timeout].is_a?(Integer)
274
+ end
275
+
276
+ #
277
+ # Misc helper methods
278
+ #
279
+ def encode(p)
280
+ text = Base64.encode64(Marshal.dump(p))
281
+ retval = nil
282
+ retries = 0
283
+ begin
284
+ retval = @compressor.deflate(text)
285
+ retries += 1
286
+ end until !(retval.nil? || retval.empty?) || (retries > 5)
287
+ retval
288
+ end
289
+
290
+ def decode(ser_obj)
291
+ text = nil
292
+ retries = 0
293
+ begin
294
+ text = @decompressor.inflate(ser_obj)
295
+ retries += 1
296
+ end until !(text.nil? || text.empty?) || (retries > 5)
297
+ Marshal.load(Base64.decode64(text))
298
+ end
299
+
300
+ def is_a_link?(s)
301
+ return false unless s.is_a? String
302
+ (s[0..6] == "http://") || (s[0..7] == "https://")
303
+ end
304
+
305
+ def generate_queue_name(opts)
306
+ q_name = opts[:name] || random_name
307
+ if opts[:namespace] && opts[:localize_queue]
308
+ "#{@namespace}-#{Digest::MD5.hexdigest(local_ip)}-#{q_name}"
309
+ elsif opts[:namespace]
310
+ "#{@namespace}-#{q_name}"
311
+ elsif opts[:localize_queue]
312
+ "#{Digest::MD5.hexdigest(local_ip)}-#{q_name}"
313
+ else
314
+ q_name
315
+ end
316
+ end
317
+
318
+ #
319
+ # Virtul attributes and convenience methods
320
+ #
321
+ def q_url
322
+ return @q_url if @q_url
323
+ @q_url = @sqs_queue.body['QueueUrl']
324
+ @q_url
325
+ end
326
+
327
+ def random_name
328
+ o = [('a'..'z'),('A'..'Z')].map{|i| i.to_a}.flatten
329
+ (0...15).map{ o[rand(o.length)] }.join
330
+ end
331
+
298
332
  def queue_name
299
333
  @queue_name
300
334
  end
301
335
 
302
- def clear_in_buffer
303
- while !@in_buffer.empty? do
304
- send_message_to_queue
336
+ def local_ip
337
+ orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true # turn off reverse DNS resolution temporarily
338
+ return "127.0.0.1" if SuperQueue.mocking?
339
+ UDPSocket.open do |s|
340
+ s.connect '64.233.187 .99', 1
341
+ s.addr.last
305
342
  end
343
+ ensure
344
+ Socket.do_not_reverse_lookup = orig
306
345
  end
307
346
 
308
- def clear_deletion_queue
309
- while !@deletion_queue.empty?
310
- @sqs.delete_message(q_url, @deletion_queue.shift)
347
+ #
348
+ # Maintence thread-related methods
349
+ #
350
+ def poll_sqs
351
+ loop do
352
+ @mutex.synchronize { fill_out_buffer_from_sqs_queue || fill_out_buffer_from_in_buffer } if @out_buffer.empty?
353
+ @mutex.synchronize { clear_in_buffer } if !@in_buffer.empty? && (@in_buffer.size > @buffer_size)
354
+ Thread.pass
311
355
  end
312
356
  end
313
357
 
358
+ def collect_garbage
359
+ loop do
360
+ #This also needs a condition to clear the del queue if there are any handles where the invisibility is about to expire
361
+ @mutex.synchronize { clear_deletion_queue } if !@deletion_queue.empty? && (@deletion_queue.size >= (@buffer_size / 2))
362
+ sleep
363
+ end
364
+ end
314
365
  end
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.0.9
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-02-10 00:00:00.000000000 Z
12
+ date: 2013-02-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: fog