aws 2.4.4 → 2.4.5
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/awsbase/awsbase.rb +7 -7
- data/lib/awsbase/errors.rb +291 -287
- data/lib/sqs/sqs.rb +150 -145
- data/lib/sqs/sqs_interface.rb +2 -2
- data/test/sqs/test_sqs.rb +7 -0
- metadata +11 -11
data/lib/awsbase/awsbase.rb
CHANGED
@@ -323,14 +323,14 @@ module Aws
|
|
323
323
|
# - :pull_out_array => an array of levels to dig into when generating return value (see rds.rb for example)
|
324
324
|
def request_info_xml_simple(connection_name, lib_params, request, logger, params = {})
|
325
325
|
|
326
|
-
|
326
|
+
connection = get_conn(connection_name, lib_params, logger)
|
327
327
|
begin
|
328
328
|
@last_request = request[:request]
|
329
329
|
@last_response = nil
|
330
330
|
|
331
|
-
response =
|
331
|
+
response = connection.request(request)
|
332
332
|
# puts "response=" + response.body
|
333
|
-
# benchblock.service.add!{ response =
|
333
|
+
# benchblock.service.add!{ response = connection.request(request) }
|
334
334
|
# check response for errors...
|
335
335
|
@last_response = response
|
336
336
|
if response.is_a?(Net::HTTPSuccess)
|
@@ -395,7 +395,7 @@ module Aws
|
|
395
395
|
raise AwsError2.new(@last_response.code, @last_request_id, request_text_data, @last_response.body)
|
396
396
|
end
|
397
397
|
ensure
|
398
|
-
|
398
|
+
connection.finish if connection && lib_params[:connection_mode] == :per_request
|
399
399
|
end
|
400
400
|
|
401
401
|
end
|
@@ -472,7 +472,7 @@ module Aws
|
|
472
472
|
|
473
473
|
|
474
474
|
def request_info_impl(connection, benchblock, request, parser, options={}, &block) #:nodoc:
|
475
|
-
|
475
|
+
connection = connection
|
476
476
|
@last_request = request[:request]
|
477
477
|
@last_response = nil
|
478
478
|
response =nil
|
@@ -489,7 +489,7 @@ module Aws
|
|
489
489
|
# Exceptions can originate from code directly in the block, or from user
|
490
490
|
# code called in the other block which is passed to response.read_body.
|
491
491
|
benchblock.service.add! do
|
492
|
-
responsehdr =
|
492
|
+
responsehdr = connection.request(request) do |response|
|
493
493
|
#########
|
494
494
|
begin
|
495
495
|
@last_response = response
|
@@ -522,7 +522,7 @@ module Aws
|
|
522
522
|
return parser.result
|
523
523
|
end
|
524
524
|
else
|
525
|
-
benchblock.service.add! { response =
|
525
|
+
benchblock.service.add! { response = connection.request(request) }
|
526
526
|
# check response for errors...
|
527
527
|
@last_response = response
|
528
528
|
if response.is_a?(Net::HTTPSuccess)
|
data/lib/awsbase/errors.rb
CHANGED
@@ -1,288 +1,292 @@
|
|
1
|
-
module Aws
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
#
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
@
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
#
|
52
|
-
#
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
aws.
|
65
|
-
aws.
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
attr_reader :
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
#
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
def self.reiteration_start_delay
|
129
|
-
@@reiteration_start_delay
|
130
|
-
end
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
def self.reiteration_time
|
139
|
-
@@reiteration_time
|
140
|
-
end
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
def self.close_on_error
|
149
|
-
@@close_on_error
|
150
|
-
end
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
def self.close_on_4xx_probability
|
159
|
-
@@close_on_4xx_probability
|
160
|
-
end
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
#
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
@
|
173
|
-
@
|
174
|
-
@
|
175
|
-
|
176
|
-
@
|
177
|
-
@
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
@aws.class.
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
#
|
244
|
-
if
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
1
|
+
module Aws
|
2
|
+
|
3
|
+
class ResourceNotFoundError < StandardError
|
4
|
+
|
5
|
+
end
|
6
|
+
|
7
|
+
# Exception class to signal any Amazon errors. All errors occuring during calls to Amazon's
|
8
|
+
# web services raise this type of error.
|
9
|
+
# Attribute inherited by RuntimeError:
|
10
|
+
# message - the text of the error, generally as returned by AWS in its XML response.
|
11
|
+
class AwsError < RuntimeError
|
12
|
+
|
13
|
+
# either an array of errors where each item is itself an array of [code, message]),
|
14
|
+
# or an error string if the error was raised manually, as in <tt>AwsError.new('err_text')</tt>
|
15
|
+
attr_reader :errors
|
16
|
+
|
17
|
+
# Request id (if exists)
|
18
|
+
attr_reader :request_id
|
19
|
+
|
20
|
+
# Response HTTP error code
|
21
|
+
attr_reader :http_code
|
22
|
+
|
23
|
+
# Raw request text data to AWS
|
24
|
+
attr_reader :request_data
|
25
|
+
|
26
|
+
attr_reader :response
|
27
|
+
|
28
|
+
def initialize(errors=nil, http_code=nil, request_id=nil, request_data=nil, response=nil)
|
29
|
+
@errors = errors
|
30
|
+
@request_id = request_id
|
31
|
+
@http_code = http_code
|
32
|
+
@request_data = request_data
|
33
|
+
@response = response
|
34
|
+
msg = @errors.is_a?(Array) ? @errors.map { |code, msg| "#{code}: #{msg}" }.join("; ") : @errors.to_s
|
35
|
+
msg += "\nREQUEST=#{@request_data} " unless @request_data.nil?
|
36
|
+
msg += "\nREQUEST ID=#{@request_id} " unless @request_id.nil?
|
37
|
+
super(msg)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Does any of the error messages include the regexp +pattern+?
|
41
|
+
# Used to determine whether to retry request.
|
42
|
+
def include?(pattern)
|
43
|
+
if @errors.is_a?(Array)
|
44
|
+
@errors.each { |code, msg| return true if code =~ pattern }
|
45
|
+
else
|
46
|
+
return true if @errors_str =~ pattern
|
47
|
+
end
|
48
|
+
false
|
49
|
+
end
|
50
|
+
|
51
|
+
# Generic handler for AwsErrors. +aws+ is the Aws::S3, Aws::EC2, or Aws::SQS
|
52
|
+
# object that caused the exception (it must provide last_request and last_response). Supported
|
53
|
+
# boolean options are:
|
54
|
+
# * <tt>:log</tt> print a message into the log using aws.logger to access the Logger
|
55
|
+
# * <tt>:puts</tt> do a "puts" of the error
|
56
|
+
# * <tt>:raise</tt> re-raise the error after logging
|
57
|
+
def self.on_aws_exception(aws, options={:raise=>true, :log=>true})
|
58
|
+
# Only log & notify if not user error
|
59
|
+
if !options[:raise] || system_error?($!)
|
60
|
+
error_text = "#{$!.inspect}\n#{$@}.join('\n')}"
|
61
|
+
puts error_text if options[:puts]
|
62
|
+
# Log the error
|
63
|
+
if options[:log]
|
64
|
+
request = aws.last_request ? aws.last_request.path : '-none-'
|
65
|
+
response = aws.last_response ? "#{aws.last_response.code} -- #{aws.last_response.message} -- #{aws.last_response.body}" : '-none-'
|
66
|
+
@response = response
|
67
|
+
aws.logger.error error_text
|
68
|
+
aws.logger.error "Request was: #{request}"
|
69
|
+
aws.logger.error "Response was: #{response}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
raise if options[:raise] # re-raise an exception
|
73
|
+
return nil
|
74
|
+
end
|
75
|
+
|
76
|
+
# True if e is an AWS system error, i.e. something that is for sure not the caller's fault.
|
77
|
+
# Used to force logging.
|
78
|
+
def self.system_error?(e)
|
79
|
+
!e.is_a?(self) || e.message =~ /InternalError|InsufficientInstanceCapacity|Unavailable/
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
# Simplified version
|
85
|
+
class AwsError2 < RuntimeError
|
86
|
+
# Request id (if exists)
|
87
|
+
attr_reader :request_id
|
88
|
+
|
89
|
+
# Response HTTP error code
|
90
|
+
attr_reader :http_code
|
91
|
+
|
92
|
+
# Raw request text data to AWS
|
93
|
+
attr_reader :request_data
|
94
|
+
|
95
|
+
attr_reader :response
|
96
|
+
|
97
|
+
attr_reader :errors
|
98
|
+
|
99
|
+
def initialize(http_code=nil, request_id=nil, request_data=nil, response=nil)
|
100
|
+
|
101
|
+
@request_id = request_id
|
102
|
+
@http_code = http_code
|
103
|
+
@request_data = request_data
|
104
|
+
@response = response
|
105
|
+
# puts '@response=' + @response.inspect
|
106
|
+
|
107
|
+
if @response
|
108
|
+
ref = XmlSimple.xml_in(@response, {"ForceArray"=>false})
|
109
|
+
# puts "refxml=" + ref.inspect
|
110
|
+
msg = "#{ref['Error']['Code']}: #{ref['Error']['Message']}"
|
111
|
+
else
|
112
|
+
msg = "#{@http_code}: REQUEST(#{@request_data})"
|
113
|
+
end
|
114
|
+
msg += "\nREQUEST ID=#{@request_id} " unless @request_id.nil?
|
115
|
+
super(msg)
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
class AWSErrorHandler
|
123
|
+
# 0-100 (%)
|
124
|
+
DEFAULT_CLOSE_ON_4XX_PROBABILITY = 10
|
125
|
+
|
126
|
+
@@reiteration_start_delay = 0.2
|
127
|
+
|
128
|
+
def self.reiteration_start_delay
|
129
|
+
@@reiteration_start_delay
|
130
|
+
end
|
131
|
+
|
132
|
+
def self.reiteration_start_delay=(reiteration_start_delay)
|
133
|
+
@@reiteration_start_delay = reiteration_start_delay
|
134
|
+
end
|
135
|
+
|
136
|
+
@@reiteration_time = 5
|
137
|
+
|
138
|
+
def self.reiteration_time
|
139
|
+
@@reiteration_time
|
140
|
+
end
|
141
|
+
|
142
|
+
def self.reiteration_time=(reiteration_time)
|
143
|
+
@@reiteration_time = reiteration_time
|
144
|
+
end
|
145
|
+
|
146
|
+
@@close_on_error = true
|
147
|
+
|
148
|
+
def self.close_on_error
|
149
|
+
@@close_on_error
|
150
|
+
end
|
151
|
+
|
152
|
+
def self.close_on_error=(close_on_error)
|
153
|
+
@@close_on_error = close_on_error
|
154
|
+
end
|
155
|
+
|
156
|
+
@@close_on_4xx_probability = DEFAULT_CLOSE_ON_4XX_PROBABILITY
|
157
|
+
|
158
|
+
def self.close_on_4xx_probability
|
159
|
+
@@close_on_4xx_probability
|
160
|
+
end
|
161
|
+
|
162
|
+
def self.close_on_4xx_probability=(close_on_4xx_probability)
|
163
|
+
@@close_on_4xx_probability = close_on_4xx_probability
|
164
|
+
end
|
165
|
+
|
166
|
+
# params:
|
167
|
+
# :reiteration_time
|
168
|
+
# :errors_list
|
169
|
+
# :close_on_error = true | false
|
170
|
+
# :close_on_4xx_probability = 1-100
|
171
|
+
def initialize(aws, parser, params={}) #:nodoc:
|
172
|
+
@aws = aws # Link to RightEc2 | RightSqs | RightS3 instance
|
173
|
+
@parser = parser # parser to parse Amazon response
|
174
|
+
@started_at = Time.now
|
175
|
+
@stop_at = @started_at + (params[:reiteration_time] || @@reiteration_time)
|
176
|
+
@errors_list = params[:errors_list] || []
|
177
|
+
@reiteration_delay = @@reiteration_start_delay
|
178
|
+
@retries = 0
|
179
|
+
# close current HTTP(S) connection on 5xx, errors from list and 4xx errors
|
180
|
+
@close_on_error = params[:close_on_error].nil? ? @@close_on_error : params[:close_on_error]
|
181
|
+
@close_on_4xx_probability = params[:close_on_4xx_probability] || @@close_on_4xx_probability
|
182
|
+
end
|
183
|
+
|
184
|
+
# Returns false if
|
185
|
+
def check(request, options={}) #:nodoc:
|
186
|
+
result = false
|
187
|
+
error_found = false
|
188
|
+
redirect_detected = false
|
189
|
+
error_match = nil
|
190
|
+
last_errors_text = ''
|
191
|
+
response = @aws.last_response
|
192
|
+
# log error
|
193
|
+
request_text_data = "#{request[:server]}:#{request[:port]}#{request[:request].path}"
|
194
|
+
# is this a redirect?
|
195
|
+
# yes!
|
196
|
+
if response.is_a?(Net::HTTPRedirection)
|
197
|
+
redirect_detected = true
|
198
|
+
else
|
199
|
+
# no, it's an error ...
|
200
|
+
@aws.logger.warn("##### #{@aws.class.name} returned an error: #{response.code} #{response.message}\n#{response.body} #####")
|
201
|
+
@aws.logger.warn("##### #{@aws.class.name} request: #{request_text_data} ####")
|
202
|
+
end
|
203
|
+
# Check response body: if it is an Amazon XML document or not:
|
204
|
+
if redirect_detected || (response.body && response.body[/<\?xml/]) # ... it is a xml document
|
205
|
+
@aws.class.bench_xml.add! do
|
206
|
+
error_parser = RightErrorResponseParser.new
|
207
|
+
error_parser.parse(response)
|
208
|
+
@aws.last_errors = error_parser.errors
|
209
|
+
@aws.last_request_id = error_parser.requestID
|
210
|
+
last_errors_text = @aws.last_errors.flatten.join("\n")
|
211
|
+
# on redirect :
|
212
|
+
if redirect_detected
|
213
|
+
location = response['location']
|
214
|
+
# ... log information and ...
|
215
|
+
@aws.logger.info("##### #{@aws.class.name} redirect requested: #{response.code} #{response.message} #####")
|
216
|
+
@aws.logger.info("##### New location: #{location} #####")
|
217
|
+
# ... fix the connection data
|
218
|
+
request[:server] = URI.parse(location).host
|
219
|
+
request[:protocol] = URI.parse(location).scheme
|
220
|
+
request[:port] = URI.parse(location).port
|
221
|
+
end
|
222
|
+
end
|
223
|
+
else # ... it is not a xml document(probably just a html page?)
|
224
|
+
@aws.last_errors = [[response.code, "#{response.message} (#{request_text_data})"]]
|
225
|
+
@aws.last_request_id = '-undefined-'
|
226
|
+
last_errors_text = response.message
|
227
|
+
end
|
228
|
+
# now - check the error
|
229
|
+
unless redirect_detected
|
230
|
+
@errors_list.each do |error_to_find|
|
231
|
+
if last_errors_text[/#{error_to_find}/i]
|
232
|
+
error_found = true
|
233
|
+
error_match = error_to_find
|
234
|
+
@aws.logger.warn("##### Retry is needed, error pattern match: #{error_to_find} #####")
|
235
|
+
break
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
# check the time has gone from the first error come
|
240
|
+
if redirect_detected || error_found
|
241
|
+
# Close the connection to the server and recreate a new one.
|
242
|
+
# It may have a chance that one server is a semi-down and reconnection
|
243
|
+
# will help us to connect to the other server
|
244
|
+
if !redirect_detected && @close_on_error
|
245
|
+
@aws.connection.finish "#{self.class.name}: error match to pattern '#{error_match}'"
|
246
|
+
end
|
247
|
+
# puts 'OPTIONS3=' + options.inspect
|
248
|
+
if options[:retries].nil? || @retries < options[:retries]
|
249
|
+
if (Time.now < @stop_at)
|
250
|
+
@retries += 1
|
251
|
+
unless redirect_detected
|
252
|
+
@aws.logger.warn("##### Retry ##{@retries} is being performed. Sleeping for #{@reiteration_delay} sec. Whole time: #{Time.now-@started_at} sec ####")
|
253
|
+
sleep @reiteration_delay
|
254
|
+
@reiteration_delay *= 2
|
255
|
+
|
256
|
+
# Always make sure that the fp is set to point to the beginning(?)
|
257
|
+
# of the File/IO. TODO: it assumes that offset is 0, which is bad.
|
258
|
+
if (request[:request].body_stream && request[:request].body_stream.respond_to?(:pos))
|
259
|
+
begin
|
260
|
+
request[:request].body_stream.pos = 0
|
261
|
+
rescue Exception => e
|
262
|
+
@logger.warn("Retry may fail due to unable to reset the file pointer" +
|
263
|
+
" -- #{self.class.name} : #{e.inspect}")
|
264
|
+
end
|
265
|
+
end
|
266
|
+
else
|
267
|
+
@aws.logger.info("##### Retry ##{@retries} is being performed due to a redirect. ####")
|
268
|
+
end
|
269
|
+
result = @aws.request_info(request, @parser, options)
|
270
|
+
else
|
271
|
+
@aws.logger.warn("##### Ooops, time is over... ####")
|
272
|
+
end
|
273
|
+
else
|
274
|
+
@aws.logger.info("##### Stopped retrying because retries=#{@retries} and max=#{options[:retries]} ####")
|
275
|
+
end
|
276
|
+
# aha, this is unhandled error:
|
277
|
+
elsif @close_on_error
|
278
|
+
# Is this a 5xx error ?
|
279
|
+
if @aws.last_response.code.to_s[/^5\d\d$/]
|
280
|
+
@aws.connection.finish "#{self.class.name}: code: #{@aws.last_response.code}: '#{@aws.last_response.message}'"
|
281
|
+
# Is this a 4xx error ?
|
282
|
+
elsif @aws.last_response.code.to_s[/^4\d\d$/] && @close_on_4xx_probability > rand(100)
|
283
|
+
@aws.connection.finish "#{self.class.name}: code: #{@aws.last_response.code}: '#{@aws.last_response.message}', " +
|
284
|
+
"probability: #{@close_on_4xx_probability}%"
|
285
|
+
end
|
286
|
+
end
|
287
|
+
result
|
288
|
+
end
|
289
|
+
|
290
|
+
end
|
291
|
+
|
288
292
|
end
|
data/lib/sqs/sqs.rb
CHANGED
@@ -23,46 +23,46 @@
|
|
23
23
|
|
24
24
|
module Aws
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
26
|
+
#
|
27
|
+
# Aws::Sqs -- RightScale's Amazon SQS interface, API version
|
28
|
+
# 2008-01-01 and later.
|
29
|
+
# The Aws::Sqs class provides a complete interface to the second generation of Amazon's Simple
|
30
|
+
# Queue Service.
|
31
|
+
# For explanations of the semantics
|
32
|
+
# of each call, please refer to Amazon's documentation at
|
33
|
+
# http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=31
|
34
|
+
#
|
35
|
+
#
|
36
|
+
# Aws::Sqs is built atop Aws::SqsInterface, a lower-level
|
37
|
+
# procedural API that may be appropriate for certain programs.
|
38
|
+
#
|
39
|
+
# Error handling: all operations raise an Aws::AwsError in case
|
40
|
+
# of problems. Note that transient errors are automatically retried.
|
41
|
+
#
|
42
|
+
# sqs = Aws::Sqs.new(aws_access_key_id, aws_secret_access_key)
|
43
|
+
# queue1 = sqs.queue('my_awesome_queue')
|
44
|
+
# ...
|
45
|
+
# queue2 = Aws::Sqs::Queue.create(sqs, 'my_cool_queue', true)
|
46
|
+
# puts queue2.size
|
47
|
+
# ...
|
48
|
+
# message1 = queue2.receive
|
49
|
+
# message1.visibility = 0
|
50
|
+
# puts message1
|
51
|
+
# ...
|
52
|
+
# queue2.clear(true)
|
53
|
+
# queue2.send_message('Ola-la!')
|
54
|
+
# message2 = queue2.pop
|
55
|
+
# ...
|
56
|
+
#
|
57
|
+
# NB: Second-generation SQS has eliminated the entire access grant mechanism present in Gen 1.
|
58
|
+
#
|
59
|
+
# Params is a hash:
|
60
|
+
#
|
61
|
+
# {:server => 'queue.amazonaws.com' # Amazon service host: 'queue.amazonaws.com' (default)
|
62
|
+
# :port => 443 # Amazon service port: 80 or 443 (default)
|
63
|
+
# :multi_thread => true|false # Multi-threaded (connection per each thread): true or false (default)
|
64
|
+
# :signature_version => '0' # The signature version : '0' or '1'(default)
|
65
|
+
# :logger => Logger Object} # Logger instance: logs to STDOUT if omitted }
|
66
66
|
class Sqs
|
67
67
|
attr_reader :interface
|
68
68
|
|
@@ -70,26 +70,29 @@ module Aws
|
|
70
70
|
@interface = SqsInterface.new(aws_access_key_id, aws_secret_access_key, params)
|
71
71
|
end
|
72
72
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
73
|
+
# Retrieves a list of queues.
|
74
|
+
# Returns an +array+ of +Queue+ instances.
|
75
|
+
#
|
76
|
+
# Aws::Sqs.queues #=> array of queues
|
77
|
+
#
|
78
78
|
def queues(prefix=nil)
|
79
79
|
@interface.list_queues(prefix).map do |url|
|
80
80
|
Queue.new(self, url)
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
84
|
+
# Returns Queue instance by queue name.
|
85
|
+
# If the queue does not exist at Amazon SQS and +create+ is true, the method creates it.
|
86
|
+
#
|
87
|
+
# Aws::Sqs.queue('my_awesome_queue') #=> #<Aws::Sqs::Queue:0xb7b626e4 ... >
|
88
|
+
#
|
89
89
|
def queue(queue_name, create=true, visibility=nil)
|
90
|
-
|
91
|
-
|
92
|
-
|
90
|
+
if create
|
91
|
+
url = @interface.create_queue(queue_name, visibility) # this returns the url even if it exists
|
92
|
+
else
|
93
|
+
url = @interface.queue_url_by_name(queue_name)
|
94
|
+
end
|
95
|
+
|
93
96
|
url ? Queue.new(self, url) : nil
|
94
97
|
end
|
95
98
|
|
@@ -97,62 +100,63 @@ module Aws
|
|
97
100
|
class Queue
|
98
101
|
attr_reader :name, :url, :sqs
|
99
102
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
103
|
+
# Returns Queue instance by queue name.
|
104
|
+
# If the queue does not exist at Amazon SQS and +create+ is true, the method creates it.
|
105
|
+
#
|
106
|
+
# Aws::Sqs::Queue.create(sqs, 'my_awesome_queue') #=> #<Aws::Sqs::Queue:0xb7b626e4 ... >
|
107
|
+
#
|
105
108
|
def self.create(sqs, url_or_name, create=true, visibility=nil)
|
106
109
|
sqs.queue(url_or_name, create, visibility)
|
107
110
|
end
|
108
111
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
112
|
+
# Creates new Queue instance.
|
113
|
+
# Does not create a queue at Amazon.
|
114
|
+
#
|
115
|
+
# queue = Aws::Sqs::Queue.new(sqs, 'my_awesome_queue')
|
116
|
+
#
|
114
117
|
def initialize(sqs, url_or_name)
|
115
|
-
@sqs
|
116
|
-
@url
|
118
|
+
@sqs = sqs
|
119
|
+
@url = @sqs.interface.queue_url_by_name(url_or_name)
|
120
|
+
raise ResourceNotFoundError, "Queue '#{url_or_name}' not found." unless @url
|
117
121
|
@name = @sqs.interface.queue_name_by_url(@url)
|
118
122
|
end
|
119
123
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
+
# Retrieves queue size.
|
125
|
+
#
|
126
|
+
# queue.size #=> 1
|
127
|
+
#
|
124
128
|
def size
|
125
129
|
@sqs.interface.get_queue_length(@url)
|
126
130
|
end
|
127
131
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
132
|
+
# Clears queue, deleting only the visible messages. Any message within its visibility
|
133
|
+
# timeout will not be deleted, and will re-appear in the queue in the
|
134
|
+
# future when the timeout expires.
|
135
|
+
#
|
136
|
+
# To delete all messages in a queue and eliminate the chance of any
|
137
|
+
# messages re-appearing in the future, it's best to delete the queue and
|
138
|
+
# re-create it as a new queue. Note that doing this will take at least 60
|
139
|
+
# s since SQS does not allow re-creation of a queue within this interval.
|
140
|
+
#
|
141
|
+
# queue.clear() #=> true
|
142
|
+
#
|
139
143
|
def clear()
|
140
|
-
|
144
|
+
@sqs.interface.clear_queue(@url)
|
141
145
|
end
|
142
146
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
147
|
+
# Deletes queue. Any messages in the queue will be permanently lost.
|
148
|
+
# Returns +true+.
|
149
|
+
#
|
150
|
+
# NB: Use with caution; severe data loss is possible!
|
151
|
+
#
|
152
|
+
# queue.delete(true) #=> true
|
153
|
+
#
|
150
154
|
def delete(force=false)
|
151
155
|
@sqs.interface.delete_queue(@url)
|
152
156
|
end
|
153
157
|
|
154
|
-
|
155
|
-
|
158
|
+
# Sends new message to queue.
|
159
|
+
# Returns new Message instance that has been sent to queue.
|
156
160
|
def send_message(message)
|
157
161
|
message = message.to_s
|
158
162
|
res = @sqs.interface.send_message(@url, message)
|
@@ -161,13 +165,14 @@ module Aws
|
|
161
165
|
msg.sent_at = Time.now
|
162
166
|
msg
|
163
167
|
end
|
168
|
+
|
164
169
|
alias_method :push, :send_message
|
165
170
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
+
# Retrieves several messages from queue.
|
172
|
+
# Returns an array of Message instances.
|
173
|
+
#
|
174
|
+
# queue.receive_messages(2,10) #=> array of messages
|
175
|
+
#
|
171
176
|
def receive_messages(number_of_messages=1, visibility=nil)
|
172
177
|
list = @sqs.interface.receive_message(@url, number_of_messages, visibility)
|
173
178
|
list.map! do |entry|
|
@@ -179,74 +184,74 @@ module Aws
|
|
179
184
|
end
|
180
185
|
end
|
181
186
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
+
# Retrieves first accessible message from queue.
|
188
|
+
# Returns Message instance or +nil+ it the queue is empty.
|
189
|
+
#
|
190
|
+
# queue.receive #=> #<Aws::Sqs::Message:0xb7bf0884 ... >
|
191
|
+
#
|
187
192
|
def receive(visibility=nil)
|
188
193
|
list = receive_messages(1, visibility)
|
189
194
|
list.empty? ? nil : list[0]
|
190
195
|
end
|
191
196
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
+
# Pops (and deletes) first accessible message from queue.
|
198
|
+
# Returns Message instance or +nil+ if the queue is empty.
|
199
|
+
#
|
200
|
+
# queue.pop #=> #<Aws::Sqs::Message:0xb7bf0884 ... >
|
201
|
+
#
|
197
202
|
def pop
|
198
203
|
list = @sqs.interface.pop_messages(@url, 1)
|
199
204
|
return nil if list.empty?
|
200
205
|
entry = list[0]
|
201
206
|
msg = Message.new(self, entry['MessageId'], entry['ReceiptHandle'],
|
202
|
-
|
207
|
+
entry['Body'], visibility)
|
203
208
|
msg.received_at = Time.now
|
204
209
|
msg.receive_checksum = entry['MD5OfBody']
|
205
210
|
msg
|
206
211
|
end
|
207
212
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
+
# Retrieves +VisibilityTimeout+ value for the queue.
|
214
|
+
# Returns new timeout value.
|
215
|
+
#
|
216
|
+
# queue.visibility #=> 30
|
217
|
+
#
|
213
218
|
def visibility
|
214
219
|
@sqs.interface.get_queue_attributes(@url, 'VisibilityTimeout')['VisibilityTimeout']
|
215
220
|
end
|
216
221
|
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
222
|
+
# Sets new +VisibilityTimeout+ for the queue.
|
223
|
+
# Returns new timeout value.
|
224
|
+
#
|
225
|
+
# queue.visibility #=> 30
|
226
|
+
# queue.visibility = 33
|
227
|
+
# queue.visibility #=> 33
|
228
|
+
#
|
224
229
|
def visibility=(visibility_timeout)
|
225
230
|
@sqs.interface.set_queue_attributes(@url, 'VisibilityTimeout', visibility_timeout)
|
226
231
|
visibility_timeout
|
227
232
|
end
|
228
233
|
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
234
|
+
# Sets new queue attribute value.
|
235
|
+
# Not all attributes may be changed: +ApproximateNumberOfMessages+ (for example) is a read only attribute.
|
236
|
+
# Returns a value to be assigned to attribute.
|
237
|
+
# Currently, 'VisibilityTimeout' is the only settable queue attribute.
|
238
|
+
# Attempting to set non-existent attributes generates an indignant
|
239
|
+
# exception.
|
240
|
+
#
|
241
|
+
# queue.set_attribute('VisibilityTimeout', '100') #=> '100'
|
242
|
+
# queue.get_attribute('VisibilityTimeout') #=> '100'
|
243
|
+
#
|
239
244
|
def set_attribute(attribute, value)
|
240
245
|
@sqs.interface.set_queue_attributes(@url, attribute, value)
|
241
246
|
value
|
242
247
|
end
|
243
248
|
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
249
|
+
# Retrieves queue attributes.
|
250
|
+
# At this moment Amazon supports +VisibilityTimeout+ and +ApproximateNumberOfMessages+ only.
|
251
|
+
# If the name of attribute is set, returns its value. Otherwise, returns a hash of attributes.
|
252
|
+
#
|
253
|
+
# queue.get_attribute('VisibilityTimeout') #=> {"VisibilityTimeout"=>"45"}
|
254
|
+
#
|
250
255
|
def get_attribute(attribute='All')
|
251
256
|
attributes = @sqs.interface.get_queue_attributes(@url, attribute)
|
252
257
|
attribute=='All' ? attributes : attributes[attribute]
|
@@ -254,37 +259,37 @@ module Aws
|
|
254
259
|
end
|
255
260
|
|
256
261
|
class Message
|
257
|
-
attr_reader
|
262
|
+
attr_reader :queue, :id, :body, :visibility, :receipt_handle
|
258
263
|
attr_accessor :sent_at, :received_at, :send_checksum, :receive_checksum
|
259
264
|
|
260
265
|
def initialize(queue, id=nil, rh = nil, body=nil, visibility=nil)
|
261
|
-
@queue
|
262
|
-
@id
|
266
|
+
@queue = queue
|
267
|
+
@id = id
|
263
268
|
@receipt_handle = rh
|
264
|
-
@body
|
265
|
-
@visibility
|
266
|
-
@sent_at
|
269
|
+
@body = body
|
270
|
+
@visibility = visibility
|
271
|
+
@sent_at = nil
|
267
272
|
@received_at = nil
|
268
273
|
@send_checksum = nil
|
269
274
|
@receive_checksum = nil
|
270
275
|
end
|
271
276
|
|
272
|
-
|
277
|
+
# Returns +Message+ instance body.
|
273
278
|
def to_s
|
274
279
|
@body
|
275
280
|
end
|
276
281
|
|
277
|
-
|
278
|
-
|
282
|
+
# Removes message from queue.
|
283
|
+
# Returns +true+.
|
279
284
|
def delete
|
280
285
|
@queue.sqs.interface.delete_message(@queue.url, @receipt_handle) if @receipt_handle
|
281
286
|
end
|
282
|
-
|
287
|
+
|
283
288
|
# Updates visibility timeout.
|
284
289
|
def visibility=(visibility_timeout)
|
285
290
|
if @receipt_handle
|
286
291
|
@queue.sqs.interface.change_message_visibility(
|
287
|
-
|
292
|
+
@queue.url, @receipt_handle, visibility_timeout
|
288
293
|
)
|
289
294
|
@visibility = visibility_timeout
|
290
295
|
end
|
data/lib/sqs/sqs_interface.rb
CHANGED
data/test/sqs/test_sqs.rb
CHANGED
@@ -33,6 +33,13 @@ class TestSqs < Test::Unit::TestCase
|
|
33
33
|
queue_url
|
34
34
|
end
|
35
35
|
|
36
|
+
def test_on_exception_no_method_error
|
37
|
+
assert_raise Aws::ResourceNotFoundError do
|
38
|
+
Aws::Sqs::Queue.new(@s, "some_nonexistant_queue")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
|
36
43
|
|
37
44
|
#---------------------------
|
38
45
|
# Rightscale::SqsInterface
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aws
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.4.
|
4
|
+
version: 2.4.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,12 +11,12 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2011-
|
14
|
+
date: 2011-03-10 00:00:00.000000000 -08:00
|
15
15
|
default_executable:
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: uuidtools
|
19
|
-
requirement: &
|
19
|
+
requirement: &27101172 !ruby/object:Gem::Requirement
|
20
20
|
none: false
|
21
21
|
requirements:
|
22
22
|
- - ! '>='
|
@@ -24,10 +24,10 @@ dependencies:
|
|
24
24
|
version: '0'
|
25
25
|
type: :runtime
|
26
26
|
prerelease: false
|
27
|
-
version_requirements: *
|
27
|
+
version_requirements: *27101172
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: http_connection
|
30
|
-
requirement: &
|
30
|
+
requirement: &27100884 !ruby/object:Gem::Requirement
|
31
31
|
none: false
|
32
32
|
requirements:
|
33
33
|
- - ! '>='
|
@@ -35,10 +35,10 @@ dependencies:
|
|
35
35
|
version: '0'
|
36
36
|
type: :runtime
|
37
37
|
prerelease: false
|
38
|
-
version_requirements: *
|
38
|
+
version_requirements: *27100884
|
39
39
|
- !ruby/object:Gem::Dependency
|
40
40
|
name: xml-simple
|
41
|
-
requirement: &
|
41
|
+
requirement: &27100596 !ruby/object:Gem::Requirement
|
42
42
|
none: false
|
43
43
|
requirements:
|
44
44
|
- - ! '>='
|
@@ -46,10 +46,10 @@ dependencies:
|
|
46
46
|
version: '0'
|
47
47
|
type: :runtime
|
48
48
|
prerelease: false
|
49
|
-
version_requirements: *
|
49
|
+
version_requirements: *27100596
|
50
50
|
- !ruby/object:Gem::Dependency
|
51
51
|
name: activesupport
|
52
|
-
requirement: &
|
52
|
+
requirement: &27100308 !ruby/object:Gem::Requirement
|
53
53
|
none: false
|
54
54
|
requirements:
|
55
55
|
- - ! '>='
|
@@ -57,7 +57,7 @@ dependencies:
|
|
57
57
|
version: '0'
|
58
58
|
type: :runtime
|
59
59
|
prerelease: false
|
60
|
-
version_requirements: *
|
60
|
+
version_requirements: *27100308
|
61
61
|
description: AWS Ruby Library for interfacing with Amazon Web Services including EC2,
|
62
62
|
S3, SQS, SimpleDB and most of their other services as well. By http://www.appoxy.com
|
63
63
|
email: travis@appoxy.com
|
@@ -135,7 +135,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
135
135
|
version: '0'
|
136
136
|
requirements: []
|
137
137
|
rubyforge_project:
|
138
|
-
rubygems_version: 1.
|
138
|
+
rubygems_version: 1.6.2
|
139
139
|
signing_key:
|
140
140
|
specification_version: 3
|
141
141
|
summary: AWS Ruby Library for interfacing with Amazon Web Services. By http://www.appoxy.com
|