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.
- data/lib/super_queue.rb +74 -109
- metadata +4 -4
data/lib/super_queue.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
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
|
-
|
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
|
-
:
|
152
|
-
:
|
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 =
|
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
|
-
|
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.
|
170
|
+
@sqs.queues.create(queue_name, { :visibility_timeout => opts[:visibility_timeout] })
|
176
171
|
else
|
177
|
-
@sqs.
|
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
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
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
|
-
@
|
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
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
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
|
-
|
218
|
-
|
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
|
-
@
|
232
|
+
@sqs_queue.delete
|
235
233
|
end
|
236
234
|
|
237
235
|
def clear_deletion_queue
|
238
236
|
while !@deletion_queue.empty?
|
239
|
-
@
|
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
|
-
|
251
|
-
|
252
|
-
m
|
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[:
|
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
|
-
|
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
|
-
|
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
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
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
|
-
|
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.
|
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.
|
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:
|
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.
|
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.
|
26
|
+
version: 1.6.5
|
27
27
|
none: false
|
28
28
|
prerelease: false
|
29
29
|
type: :runtime
|