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.
- data/lib/super_queue.rb +123 -72
- 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
|
-
|
127
|
-
|
128
|
-
|
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 :
|
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 =>
|
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
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
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
|
303
|
-
|
304
|
-
|
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
|
-
|
309
|
-
|
310
|
-
|
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
|
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-
|
12
|
+
date: 2013-02-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: fog
|