aws 2.4.4 → 2.4.5
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/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
|