super_queue 0.0.9 → 0.1.0

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 +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