bisques 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +7 -0
- data/LICENSE +22 -0
- data/README.rdoc +1 -1
- data/lib/bisques.rb +1 -1
- data/lib/bisques/aws_connection.rb +43 -17
- data/lib/bisques/aws_credentials.rb +6 -1
- data/lib/bisques/aws_request.rb +26 -18
- data/lib/bisques/aws_response.rb +10 -8
- data/lib/bisques/client.rb +67 -12
- data/lib/bisques/message.rb +17 -7
- data/lib/bisques/queue.rb +38 -9
- data/lib/bisques/queue_listener.rb +13 -5
- metadata +21 -13
data/CHANGELOG
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Jeremy Wells
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
CHANGED
@@ -45,7 +45,7 @@ fibonacci sequence, with the consumer script doing the actual calculation.
|
|
45
45
|
|
46
46
|
== LICENSE
|
47
47
|
|
48
|
-
Copyright (c)
|
48
|
+
Copyright (c) 2013 Jeremy Wells
|
49
49
|
|
50
50
|
Permission is hereby granted, free of charge, to any person
|
51
51
|
obtaining a copy of this software and associated documentation
|
data/lib/bisques.rb
CHANGED
@@ -17,9 +17,20 @@ module Bisques
|
|
17
17
|
end
|
18
18
|
|
19
19
|
# This module is for making API classes more convenient. The including class
|
20
|
-
# must pass the correct params via super from it's #initialize call. Two
|
21
|
-
# useful methods are added to the including class, #request and #action.
|
20
|
+
# must pass the correct params via super from it's {#initialize} call. Two
|
21
|
+
# useful methods are added to the including class, {#request} and {#action}.
|
22
|
+
#
|
23
|
+
# @example
|
24
|
+
# class Sqs
|
25
|
+
# include AwsConnection
|
26
|
+
#
|
27
|
+
# def initialize(region)
|
28
|
+
# super(region, 'sqs')
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
#
|
22
32
|
module AwsConnection
|
33
|
+
# @!visibility private
|
23
34
|
def self.included(mod) # :nodoc:
|
24
35
|
mod.class_eval do
|
25
36
|
attr_accessor :credentials, :region, :service
|
@@ -28,8 +39,11 @@ module Bisques
|
|
28
39
|
|
29
40
|
# Give the region, service and optionally the AwsCredentials.
|
30
41
|
#
|
31
|
-
#
|
42
|
+
# @param [String] region the AWS region (ex. us-east-1)
|
43
|
+
# @param [String] service the AWS service (ex. sqs)
|
44
|
+
# @param [AwsCredentials] credentials
|
32
45
|
#
|
46
|
+
# @example
|
33
47
|
# class Sqs
|
34
48
|
# include AwsConnection
|
35
49
|
#
|
@@ -42,19 +56,19 @@ module Bisques
|
|
42
56
|
@region, @service, @credentials = region, service, credentials
|
43
57
|
end
|
44
58
|
|
45
|
-
def connection # :nodoc:
|
46
|
-
@connection ||= HTTPClient.new.tap do |http|
|
47
|
-
http.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
48
|
-
http.receive_timeout = 30
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
59
|
# Perform an HTTP query to the given path using the given method (GET,
|
53
60
|
# POST, PUT, DELETE). A hash of query params can be specified. A POST or
|
54
61
|
# PUT body cna be specified as either a string or a hash of form params. A
|
55
62
|
# hash of HTTP headers can be specified.
|
63
|
+
#
|
64
|
+
# @param [String] method HTTP method, should be GET, POST, PUT or DELETE
|
65
|
+
# @param [String] path
|
66
|
+
# @param [Hash] query HTTP query params to send. Specify these as a hash, do not append them to the path.
|
67
|
+
# @param [Hash,#to_s] body HTTP request body. This can be form data as a hash or a String. Only applies to POST and PUT HTTP methods.
|
68
|
+
# @param [Hash] headers additional HTTP headers to send.
|
69
|
+
# @return [AwsRequest]
|
56
70
|
def request(method, path, query = {}, body = nil, headers = {})
|
57
|
-
AwsRequest.new(
|
71
|
+
AwsRequest.new(aws_http_connection).tap do |aws_request|
|
58
72
|
aws_request.credentials = credentials
|
59
73
|
aws_request.path = path
|
60
74
|
aws_request.region = region
|
@@ -68,13 +82,17 @@ module Bisques
|
|
68
82
|
end
|
69
83
|
|
70
84
|
# Call an AWS API with the given name at the given path. An optional hash
|
71
|
-
# of options can be passed as arguments for the API call.
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
85
|
+
# of options can be passed as arguments for the API call.
|
86
|
+
#
|
87
|
+
# @note The API call will be automatically retried *once* if the returned status code is
|
88
|
+
# in the 500 range.
|
75
89
|
#
|
76
|
-
#
|
77
|
-
#
|
90
|
+
# @param [String] action_name
|
91
|
+
# @param [String] path
|
92
|
+
# @param [Hash] options
|
93
|
+
# @return [AwsResponse]
|
94
|
+
# @raise [AwsActionError] if the response is not successful. AWS error
|
95
|
+
# information can be extracted from the exception.
|
78
96
|
def action(action_name, path = "/", options = {})
|
79
97
|
retries = 0
|
80
98
|
|
@@ -96,5 +114,13 @@ module Bisques
|
|
96
114
|
end
|
97
115
|
end
|
98
116
|
end
|
117
|
+
|
118
|
+
private
|
119
|
+
def aws_http_connection
|
120
|
+
@aws_http_connection ||= HTTPClient.new.tap do |http|
|
121
|
+
http.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
122
|
+
http.receive_timeout = 30
|
123
|
+
end
|
124
|
+
end
|
99
125
|
end
|
100
126
|
end
|
@@ -2,18 +2,23 @@ module Bisques
|
|
2
2
|
# Represents an AWS key/secret combination. Provides a convenient class
|
3
3
|
# method for setting defaults that can be used by all objects later on.
|
4
4
|
#
|
5
|
-
#
|
5
|
+
# @example
|
6
6
|
#
|
7
7
|
# AwsCredentials.default('aws_key', 'aws_secret')
|
8
8
|
#
|
9
9
|
class AwsCredentials
|
10
|
+
# @return [String]
|
10
11
|
attr_reader :aws_key, :aws_secret
|
11
12
|
|
13
|
+
# @param [String] aws_key
|
14
|
+
# @param [String] aws_secret
|
12
15
|
def initialize(aws_key, aws_secret)
|
13
16
|
@aws_key, @aws_secret = aws_key, aws_secret
|
14
17
|
end
|
15
18
|
|
16
19
|
class << self
|
20
|
+
# (see #initialize)
|
21
|
+
# Set or retrieve the default credentials
|
17
22
|
def default(*args)
|
18
23
|
if args.size == 2
|
19
24
|
@default = AwsCredentials.new(*args)
|
data/lib/bisques/aws_request.rb
CHANGED
@@ -4,10 +4,10 @@ require 'bisques/aws_response'
|
|
4
4
|
module Bisques
|
5
5
|
# A request to an AWS API call. This class must be initiated with a client
|
6
6
|
# instance of HTTPClient. A number of mandatory attributes must be set before
|
7
|
-
# calling make_request to return the response. #make_request returns an
|
8
|
-
# AwsResponse object.
|
7
|
+
# calling {#make_request} to return the response. {#make_request} returns an
|
8
|
+
# {AwsResponse} object.
|
9
9
|
#
|
10
|
-
#
|
10
|
+
# @example
|
11
11
|
#
|
12
12
|
# request = AwsRequest.new(httpclient)
|
13
13
|
# request.method = "GET" or "POST"
|
@@ -18,47 +18,55 @@ module Bisques
|
|
18
18
|
# request.region = "AWS region (ex. us-east-1)"
|
19
19
|
# request.service = "AWS service (ex. sqs)"
|
20
20
|
# request.credentials = AwsCredentials.new("aws_key", "aws_secret")
|
21
|
-
# response = request.make_request
|
21
|
+
# response = request.make_request
|
22
22
|
#
|
23
23
|
class AwsRequest
|
24
|
-
# The HTTP method to use. Should be GET or POST.
|
24
|
+
# @return [String] The HTTP method to use. Should be GET or POST.
|
25
25
|
attr_accessor :method
|
26
|
-
# A hash describing the query params to send.
|
26
|
+
# @return [Hash] A hash describing the query params to send.
|
27
27
|
attr_accessor :query
|
28
|
-
# A hash or string describing the form params or HTTP body. Only used when
|
29
|
-
#
|
28
|
+
# @return [Hash,String] A hash or string describing the form params or HTTP body. Only used when
|
29
|
+
# the method is POST or PUT.
|
30
30
|
attr_accessor :body
|
31
|
-
# A hash of additional HTTP headers to send with the request.
|
31
|
+
# @return [Hash] A hash of additional HTTP headers to send with the request.
|
32
32
|
attr_accessor :headers
|
33
|
-
# The path to the API call. This shouldn't be the full URL as the host part
|
34
|
-
#
|
33
|
+
# @return [String] The path to the API call. This shouldn't be the full URL as the host part
|
34
|
+
# is built from the region and service.
|
35
35
|
attr_accessor :path
|
36
|
-
# The AWS region. Ex: us-east-1
|
36
|
+
# @return [String] The AWS region. Ex: us-east-1
|
37
37
|
attr_accessor :region
|
38
|
-
# The AWS service. Ex: sqs
|
38
|
+
# @return [String] The AWS service. Ex: sqs
|
39
39
|
attr_accessor :service
|
40
|
-
# The AWS credentials. Should respond to aws_key and aws_secret.
|
41
|
-
# AwsCredentials.
|
40
|
+
# @return [AwsCredentials] The AWS credentials. Should respond to aws_key and aws_secret.
|
42
41
|
attr_accessor :credentials
|
43
42
|
|
44
|
-
# An AwsResponse object describing the response. Returns nil until
|
45
|
-
#
|
43
|
+
# @return [AwsResponse] An AwsResponse object describing the response. Returns nil until
|
44
|
+
# {#make_request} has been called.
|
46
45
|
attr_reader :response
|
46
|
+
# @return [AwsRequestAuthorization]
|
47
|
+
# @!visibility private
|
47
48
|
attr_reader :authorization # :nodoc:
|
48
49
|
|
49
50
|
# AWS has some particular rules about how it likes it's form params encoded.
|
51
|
+
#
|
52
|
+
# @param [String] value
|
53
|
+
# @return [String] encoded value
|
50
54
|
def self.aws_encode(value)
|
51
55
|
value.to_s.gsub(/([^a-zA-Z0-9._~-]+)/n) do
|
52
56
|
'%' + $1.unpack('H2' * $1.size).join('%').upcase
|
53
57
|
end
|
54
58
|
end
|
55
59
|
|
56
|
-
# Create a new AwsRequest using the given HTTPClient object.
|
60
|
+
# Create a new {AwsRequest} using the given HTTPClient object.
|
61
|
+
#
|
62
|
+
# @param [HTTPClient] httpclient
|
57
63
|
def initialize(httpclient)
|
58
64
|
@httpclient = httpclient
|
59
65
|
end
|
60
66
|
|
61
67
|
# The full URL to the API endpoint the request will call.
|
68
|
+
#
|
69
|
+
# @return [String]
|
62
70
|
def url
|
63
71
|
File.join("https://#{service}.#{region}.amazonaws.com", path)
|
64
72
|
end
|
data/lib/bisques/aws_response.rb
CHANGED
@@ -2,14 +2,14 @@ require 'nokogiri'
|
|
2
2
|
|
3
3
|
module Bisques
|
4
4
|
# Created by an AwsRequest to represent the returned details. The original
|
5
|
-
# request is stored in #request. The raw content is available in #content.
|
6
|
-
# AWS returns XML, and a Nokogiri::XML instance is available in #doc.
|
5
|
+
# request is stored in {#request}. The raw content is available in {#content}.
|
6
|
+
# AWS returns XML, and a Nokogiri::XML instance is available in {#doc}.
|
7
7
|
class AwsResponse
|
8
|
-
# The original AwsRequest that created this response.
|
8
|
+
# @return [AwsRequest] The original AwsRequest that created this response.
|
9
9
|
attr_reader :request
|
10
|
-
# The raw response string from AWS
|
10
|
+
# @return [String] The raw response string from AWS
|
11
11
|
attr_reader :content
|
12
|
-
# The HTTP response. This can be used to get any headers or status codes.
|
12
|
+
# @return [#body,#status,#header] The HTTP response. This can be used to get any headers or status codes.
|
13
13
|
attr_reader :http_response
|
14
14
|
|
15
15
|
def initialize(request, http_response) # :nodoc:
|
@@ -18,17 +18,19 @@ module Bisques
|
|
18
18
|
@content = @http_response.body
|
19
19
|
end
|
20
20
|
|
21
|
-
# A Nokogiri::XML document parsed from the #content.
|
21
|
+
# A Nokogiri::XML document parsed from the {#content}.
|
22
|
+
#
|
23
|
+
# @return [Nokogiri::XML] XML document
|
22
24
|
def doc
|
23
25
|
@doc ||= Nokogiri::XML(content).tap{|x|x.remove_namespaces!}
|
24
26
|
end
|
25
27
|
|
26
|
-
# Returns true if the request was successful.
|
28
|
+
# @return [Boolean] Returns true if the request was successful.
|
27
29
|
def success?
|
28
30
|
@http_response.ok?
|
29
31
|
end
|
30
32
|
|
31
|
-
# The request ID from AWS.
|
33
|
+
# @return [String] The request ID from AWS.
|
32
34
|
def request_id
|
33
35
|
@http_response.header['x-amzn-RequestId']
|
34
36
|
end
|
data/lib/bisques/client.rb
CHANGED
@@ -5,25 +5,29 @@ require 'bisques/queue_listener'
|
|
5
5
|
require 'digest/md5'
|
6
6
|
|
7
7
|
module Bisques
|
8
|
+
class QueueDeletedRecentlyError << Bisques::Error
|
9
|
+
end
|
10
|
+
|
8
11
|
# Bisques is a client for Amazon SQS. All of the API calls made to SQS are
|
9
12
|
# called via methods on this class.
|
10
13
|
#
|
11
|
-
#
|
14
|
+
# @example
|
12
15
|
#
|
13
16
|
# client = Bisques::Client.new('us-east-1', 'my_queues_', AwsCredentials.new(aws_key, aws_secret))
|
14
17
|
# client.list_queues
|
15
18
|
#
|
16
19
|
class Client
|
17
|
-
# The queue prefix when interacting with SQS. The client will only be able
|
20
|
+
# @return [String] The queue prefix when interacting with SQS. The client will only be able
|
18
21
|
# to see queues whose name has this prefix.
|
19
22
|
attr_accessor :queue_prefix
|
20
23
|
|
21
24
|
include AwsConnection
|
22
25
|
|
23
|
-
# Initialize a client object.
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
26
|
+
# Initialize a client object.
|
27
|
+
#
|
28
|
+
# @param [String] region the AWS region.
|
29
|
+
# @param [String] queue_prefix an optional prefix for all queue names for this instance.
|
30
|
+
# @param [AwsCredentials] credentials an instance of AwsCredentials. Uses AwsCredentials::default if not provided.
|
27
31
|
def initialize(region, queue_prefix = nil, credentials = AwsCredentials.default)
|
28
32
|
super(region, "sqs", credentials)
|
29
33
|
@queue_prefix = queue_prefix
|
@@ -31,11 +35,20 @@ module Bisques
|
|
31
35
|
|
32
36
|
# Returns a Queue object representing an SQS queue, creating it if it does
|
33
37
|
# not already exist.
|
38
|
+
#
|
39
|
+
# @param [String] name
|
40
|
+
# @return [Queue]
|
41
|
+
# @raise [AwsActionError]
|
34
42
|
def get_or_create_queue(name)
|
35
43
|
get_queue(name) || create_queue(name, {})
|
36
44
|
end
|
37
45
|
|
38
46
|
# Creates a new SQS queue and returns a Queue object.
|
47
|
+
#
|
48
|
+
# @param [String] name
|
49
|
+
# @param [Hash] attributes
|
50
|
+
# @return [Queue]
|
51
|
+
# @raise [AwsActionError]
|
39
52
|
def create_queue(name, attributes = {})
|
40
53
|
response = action("CreateQueue", {"QueueName" => Queue.sanitize_name("#{queue_prefix}#{name}")}.merge(attributes))
|
41
54
|
|
@@ -44,14 +57,28 @@ module Bisques
|
|
44
57
|
else
|
45
58
|
raise "Could not create queue #{name}"
|
46
59
|
end
|
60
|
+
|
61
|
+
rescue AwsActionError => error
|
62
|
+
if error.code == "AWS.SimpleQueueService.QueueDeletedRecently"
|
63
|
+
raise QueueDeletedRecentlyError, error.message
|
64
|
+
else
|
65
|
+
raise error
|
66
|
+
end
|
47
67
|
end
|
48
68
|
|
49
69
|
# Deletes an SQS queue at a given path.
|
70
|
+
# @param [String] queue_url
|
71
|
+
# @return [AwsResponse]
|
72
|
+
# @raise [AwsActionError]
|
50
73
|
def delete_queue(queue_url)
|
51
74
|
response = action("DeleteQueue", queue_url)
|
52
75
|
end
|
53
76
|
|
54
|
-
# Get an SQS queue by name.
|
77
|
+
# Get an SQS queue by name.
|
78
|
+
# @param [String] name
|
79
|
+
# @param [Hash] options
|
80
|
+
# @return [Queue,nil] Returns a Queue object if the queue is found, otherwise nil.
|
81
|
+
# @raise [AwsActionError]
|
55
82
|
def get_queue(name, options = {})
|
56
83
|
response = action("GetQueueUrl", {"QueueName" => Queue.sanitize_name("#{queue_prefix}#{name}")}.merge(options))
|
57
84
|
|
@@ -67,9 +94,12 @@ module Bisques
|
|
67
94
|
# optional prefix can be supplied to restrict the queues found. This prefix
|
68
95
|
# is additional to the client prefix.
|
69
96
|
#
|
70
|
-
#
|
97
|
+
# @param [String] prefix option prefix to restrict the queues found.
|
98
|
+
# @return [Array<Queue>] queue objects found.
|
99
|
+
# @raise [AwsActionError]
|
100
|
+
#
|
101
|
+
# @example Delete all the queues
|
71
102
|
#
|
72
|
-
# # Delete all the queues
|
73
103
|
# client.list_queues.each do |queue|
|
74
104
|
# queue.delete
|
75
105
|
# end
|
@@ -84,7 +114,10 @@ module Bisques
|
|
84
114
|
# Get the attributes for a queue. Takes an array of attribute names.
|
85
115
|
# Defaults to ["All"] which returns all the available attributes.
|
86
116
|
#
|
87
|
-
#
|
117
|
+
# @param [String] queue_url
|
118
|
+
# @param [Array<String>] attributes
|
119
|
+
# @return [AwsResponse]
|
120
|
+
# @raise [AwsActionError]
|
88
121
|
def get_queue_attributes(queue_url, attributes = ["All"])
|
89
122
|
attributes = attributes.map(&:to_s)
|
90
123
|
|
@@ -99,7 +132,14 @@ module Bisques
|
|
99
132
|
# should be a string. An optional delay seconds argument can be added if
|
100
133
|
# the message should not become visible immediately.
|
101
134
|
#
|
102
|
-
#
|
135
|
+
# @param [String] queue_url
|
136
|
+
# @param [String] message_body
|
137
|
+
# @param [Fixnum] delay_seconds
|
138
|
+
# @return nil
|
139
|
+
# @raise [MessageHasWrongMd5Error]
|
140
|
+
# @raise [AwsActionError]
|
141
|
+
#
|
142
|
+
# @example
|
103
143
|
#
|
104
144
|
# client.send_message(queue.path, "test message")
|
105
145
|
#
|
@@ -127,11 +167,20 @@ module Bisques
|
|
127
167
|
|
128
168
|
# Delete a message from a queue. The message is deleted by the handle given
|
129
169
|
# when the message is retrieved.
|
170
|
+
#
|
171
|
+
# @param [String] queue_url
|
172
|
+
# @param [String] receipt_handle
|
173
|
+
# @return [AwsResponse]
|
174
|
+
# @raise [AwsActionError]
|
130
175
|
def delete_message(queue_url, receipt_handle)
|
131
|
-
|
176
|
+
action("DeleteMessage", queue_url, {"ReceiptHandle" => receipt_handle})
|
132
177
|
end
|
133
178
|
|
134
179
|
# Receive a message from a queue. Takes the queue url and an optional hash.
|
180
|
+
# @param [String] queue_url
|
181
|
+
# @param [Hash] options
|
182
|
+
# @return [AwsResponse]
|
183
|
+
# @raise [AwsActionError]
|
135
184
|
def receive_message(queue_url, options = {})
|
136
185
|
# validate_options(options, %w(AttributeName MaxNumberOfMessages VisibilityTimeout WaitTimeSeconds))
|
137
186
|
action("ReceiveMessage", queue_url, options)
|
@@ -141,6 +190,12 @@ module Bisques
|
|
141
190
|
# have retrieved a message and now want to keep it hidden for longer before
|
142
191
|
# deleting it, or if you have a job and decide you cannot action it and
|
143
192
|
# want to return it to the queue sooner.
|
193
|
+
#
|
194
|
+
# @param [String] queue_url
|
195
|
+
# @param [String] receipt_handle
|
196
|
+
# @param [Fixnum] visibility_timeout
|
197
|
+
# @return [AwsResponse]
|
198
|
+
# @raise [AwsActionError]
|
144
199
|
def change_message_visibility(queue_url, receipt_handle, visibility_timeout)
|
145
200
|
action("ChangeMessageVisibility", queue_url, {"ReceiptHandle" => receipt_handle, "VisibilityTimeout" => visibility_timeout})
|
146
201
|
end
|
data/lib/bisques/message.rb
CHANGED
@@ -3,17 +3,23 @@ require 'json'
|
|
3
3
|
module Bisques
|
4
4
|
# A message received from an SQS queue.
|
5
5
|
class Message
|
6
|
-
# The queue this message originated from.
|
6
|
+
# @return [Queue] The queue this message originated from.
|
7
7
|
attr_reader :queue
|
8
|
-
# The AWS Id of the message.
|
8
|
+
# @return [String] The AWS Id of the message.
|
9
9
|
attr_reader :id
|
10
|
-
# A unique handle used to manipulate the message.
|
10
|
+
# @return [String] A unique handle used to manipulate the message.
|
11
11
|
attr_reader :handle
|
12
|
-
# The raw text body of the message.
|
12
|
+
# @return [String] The raw text body of the message.
|
13
13
|
attr_reader :body
|
14
|
-
# Hash of SQS attributes.
|
14
|
+
# @return [Hash] Hash of SQS attributes.
|
15
15
|
attr_reader :attributes
|
16
16
|
|
17
|
+
# @api
|
18
|
+
# @param [Queue] queue
|
19
|
+
# @param [String] id
|
20
|
+
# @param [String] handle
|
21
|
+
# @param [String] body
|
22
|
+
# @param [Hash] attributes
|
17
23
|
def initialize(queue, id, handle, body, attributes = {}) #:nodoc:
|
18
24
|
@queue, @id, @handle, @body, @attributes = queue, id, handle, body, attributes
|
19
25
|
end
|
@@ -21,15 +27,17 @@ module Bisques
|
|
21
27
|
# The deserialized object in the message. This method is used to retrieve
|
22
28
|
# the contents that Queue#post_message placed there.
|
23
29
|
#
|
24
|
-
#
|
30
|
+
# @example
|
25
31
|
#
|
26
32
|
# queue.post_message([1,2,3])
|
27
|
-
# queue.retrieve.object
|
33
|
+
# queue.retrieve.object == [1,2,3]
|
28
34
|
#
|
29
35
|
def object
|
30
36
|
@object ||= JSON.parse(body)
|
31
37
|
end
|
32
38
|
|
39
|
+
# @return (see Queue#delete_message)
|
40
|
+
# @raise (see Queue#delete_message)
|
33
41
|
# Delete the message from the queue. This should be called after the
|
34
42
|
# message has been received and processed. If not then after a timeout the
|
35
43
|
# message will get added back to the queue.
|
@@ -37,6 +45,8 @@ module Bisques
|
|
37
45
|
queue.delete_message(handle)
|
38
46
|
end
|
39
47
|
|
48
|
+
# @return (see Queue#return_message)
|
49
|
+
# @raise (see Queue#return_message)
|
40
50
|
# Return the message to the queue immediately. If a client has taken a
|
41
51
|
# message and cannot process it for any reason it can put the message back
|
42
52
|
# faster than the default timeout by calling this method.
|
data/lib/bisques/queue.rb
CHANGED
@@ -11,9 +11,10 @@ module Bisques
|
|
11
11
|
end
|
12
12
|
class QueueNotFound < QueueError; end
|
13
13
|
|
14
|
-
|
14
|
+
# @!visibility private
|
15
15
|
attr_reader :client # :nodoc:
|
16
16
|
|
17
|
+
# @!visibility private
|
17
18
|
def self.sanitize_name(name)
|
18
19
|
name = name.gsub(/[^_\w\d]/, "")
|
19
20
|
|
@@ -27,18 +28,21 @@ module Bisques
|
|
27
28
|
name
|
28
29
|
end
|
29
30
|
|
30
|
-
# Queues are created by the Client passing the client itself and the url
|
31
|
+
# Queues are created by the {Client} passing the client itself and the url
|
31
32
|
# for the queue.
|
33
|
+
#
|
34
|
+
# @param [Client] client
|
35
|
+
# @param [String] url
|
32
36
|
def initialize(client, url)
|
33
37
|
@client, @url = client, url
|
34
38
|
end
|
35
39
|
|
36
|
-
# The name of the queue derived from the URL.
|
40
|
+
# @return [String] The name of the queue derived from the URL.
|
37
41
|
def name
|
38
42
|
@url.split("/").last
|
39
43
|
end
|
40
44
|
|
41
|
-
# The path part of the queue URL
|
45
|
+
# @return [String] The path part of the queue URL
|
42
46
|
def path
|
43
47
|
Addressable::URI.parse(@url).path
|
44
48
|
end
|
@@ -50,7 +54,7 @@ module Bisques
|
|
50
54
|
def ==(queue)
|
51
55
|
hash == queue.hash
|
52
56
|
end
|
53
|
-
def hash
|
57
|
+
def hash
|
54
58
|
@url.hash
|
55
59
|
end
|
56
60
|
|
@@ -63,13 +67,16 @@ module Bisques
|
|
63
67
|
# If more than one, or all, attributes are requested then a hash of
|
64
68
|
# attribute names and values is returned.
|
65
69
|
#
|
66
|
-
#
|
70
|
+
# @param [String] attributes
|
71
|
+
# @return [Object,Hash]
|
67
72
|
#
|
68
|
-
#
|
73
|
+
# @example with one attribute
|
69
74
|
#
|
70
|
-
#
|
75
|
+
# queue.attributes(:ApproximateNumberOfMessages) == 10
|
71
76
|
#
|
72
|
-
#
|
77
|
+
# @example with multiple attributes
|
78
|
+
#
|
79
|
+
# queue.attributes(:ApproximateNumberOfMessages, :ApproximateNumberOfMessagesDelayed) == {:ApproximateNumberOfMessages => 10, :ApproximateNumberOfMessagesDelayed => 5}
|
73
80
|
#
|
74
81
|
def attributes(*attributes)
|
75
82
|
return nil if attributes.blank?
|
@@ -92,18 +99,28 @@ module Bisques
|
|
92
99
|
end
|
93
100
|
|
94
101
|
# Delete the queue
|
102
|
+
# @return [AwsResponse]
|
103
|
+
# @raise [AwsActionError]
|
95
104
|
def delete
|
96
105
|
client.delete_queue(url)
|
97
106
|
end
|
98
107
|
|
99
108
|
# Post a message to the queue. The message must be serializable (i.e.
|
100
109
|
# strings, numbers, arrays, hashes).
|
110
|
+
#
|
111
|
+
# @param [String,Fixnum,Array,Hash] object
|
112
|
+
# @raise [MessageHasWrongMd5Error]
|
113
|
+
# @raise [AwsActionError]
|
101
114
|
def post_message(object)
|
102
115
|
client.send_message(url, JSON.dump(object))
|
103
116
|
end
|
104
117
|
|
105
118
|
# Retrieve a message from the queue. Returns nil if no message is waiting
|
106
119
|
# in the given poll time. Otherwise it returns a Message.
|
120
|
+
#
|
121
|
+
# @param [Fixnum] poll_time
|
122
|
+
# @return [Message,nil]
|
123
|
+
# @raise [AwsActionError]
|
107
124
|
def retrieve(poll_time = 1)
|
108
125
|
response = client.receive_message(url, {"WaitTimeSeconds" => poll_time, "MaxNumberOfMessages" => 1})
|
109
126
|
raise QueueNotFound.new(self, "not found at #{url}") if response.http_response.status == 404
|
@@ -123,6 +140,10 @@ module Bisques
|
|
123
140
|
|
124
141
|
# Retrieve a single message from the queue. This will block until a message
|
125
142
|
# arrives. The message will be of the class Message.
|
143
|
+
#
|
144
|
+
# @param [Fixnum] poll_time
|
145
|
+
# @return [Message]
|
146
|
+
# @raise [AwsActionError]
|
126
147
|
def retrieve_one(poll_time = 5)
|
127
148
|
object = nil
|
128
149
|
while object.nil?
|
@@ -134,6 +155,10 @@ module Bisques
|
|
134
155
|
# Delete a message from the queue. This should be called to confirm that
|
135
156
|
# the message has been processed. If it is not called then the message will
|
136
157
|
# get put back on the queue after a timeout.
|
158
|
+
#
|
159
|
+
# @param [String] handle
|
160
|
+
# @return [Boolean] true if the message was deleted.
|
161
|
+
# @raise [AwsActionError]
|
137
162
|
def delete_message(handle)
|
138
163
|
response = client.delete_message(url, handle)
|
139
164
|
response.success?
|
@@ -141,6 +166,10 @@ module Bisques
|
|
141
166
|
|
142
167
|
# Return a message to the queue after receiving it. This would typically
|
143
168
|
# happen if the receiver decided it couldn't process.
|
169
|
+
#
|
170
|
+
# @param [String] handle
|
171
|
+
# @return [AwsResponse]
|
172
|
+
# @raise [AwsActionError]
|
144
173
|
def return_message(handle)
|
145
174
|
client.change_message_visibility(url, handle, 0)
|
146
175
|
end
|
@@ -4,17 +4,20 @@ require 'thread'
|
|
4
4
|
module Bisques
|
5
5
|
# Listen for messages on a queue and execute a block when they arrive.
|
6
6
|
class QueueListener
|
7
|
+
# @param [Queue] queue the queue to listen on
|
8
|
+
# @param [Fixnum] poll_time the number of seconds to long poll during each iteration. Maximum is 20.
|
7
9
|
def initialize(queue, poll_time = 5)
|
8
10
|
@queue, @poll_time = queue, poll_time
|
9
11
|
end
|
10
12
|
|
13
|
+
# @return [Boolean] returns true while the listener is active.
|
11
14
|
def listening?
|
12
15
|
@listening
|
13
16
|
end
|
14
17
|
|
15
18
|
# Listen for messages. This is asynchronous and returns immediately.
|
16
19
|
#
|
17
|
-
#
|
20
|
+
# @example
|
18
21
|
#
|
19
22
|
# queue = bisques.find_or_create_queue("my queue")
|
20
23
|
# listener = QueuedListener.new(queue)
|
@@ -25,7 +28,8 @@ module Bisques
|
|
25
28
|
#
|
26
29
|
# while true; sleep 1; end # Process messages forever
|
27
30
|
#
|
28
|
-
# Note that the block you give to this method is executed in a new thread.
|
31
|
+
# @note Note that the block you give to this method is executed in a new thread.
|
32
|
+
# @yield [Message] a message received from the {Queue}
|
29
33
|
#
|
30
34
|
def listen(&block)
|
31
35
|
return if @listening
|
@@ -39,7 +43,7 @@ module Bisques
|
|
39
43
|
end
|
40
44
|
end
|
41
45
|
|
42
|
-
# Stop listening for messages
|
46
|
+
# Stop listening for messages.
|
43
47
|
def stop
|
44
48
|
@listening = false
|
45
49
|
@thread.join if @thread
|
@@ -47,9 +51,9 @@ module Bisques
|
|
47
51
|
end
|
48
52
|
|
49
53
|
# Listen for messages on several queues at the same time. The interface for
|
50
|
-
# objects of this class is identical to that of QueueListener.
|
54
|
+
# objects of this class is identical to that of {QueueListener}.
|
51
55
|
#
|
52
|
-
#
|
56
|
+
# @example
|
53
57
|
#
|
54
58
|
# queue_1 = bisques.find_or_create_queue("queue one")
|
55
59
|
# queue_2 = bisques.find_or_create_queue("queue two")
|
@@ -61,15 +65,18 @@ module Bisques
|
|
61
65
|
# while true; sleep 1; end # Process messages forever
|
62
66
|
#
|
63
67
|
class MultiQueueListener
|
68
|
+
# @param [Array<Queue>] queues
|
64
69
|
def initialize(*queues)
|
65
70
|
@queues = queues
|
66
71
|
@listeners = []
|
67
72
|
end
|
68
73
|
|
74
|
+
# (see QueueListener#listening?)
|
69
75
|
def listening?
|
70
76
|
@listeners.any?
|
71
77
|
end
|
72
78
|
|
79
|
+
# (see QueueListener#listen)
|
73
80
|
def listen(&block)
|
74
81
|
return if @listeners.any?
|
75
82
|
@listeners = @queues.map do |queue|
|
@@ -81,6 +88,7 @@ module Bisques
|
|
81
88
|
end
|
82
89
|
end
|
83
90
|
|
91
|
+
# (see QueueListener#stop)
|
84
92
|
def stop
|
85
93
|
@listeners.each(&:stop)
|
86
94
|
@listeners = []
|
metadata
CHANGED
@@ -1,96 +1,96 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bisques
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.1
|
5
4
|
prerelease:
|
5
|
+
version: 1.0.2
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Jeremy Wells
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-04-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: httpclient
|
16
|
-
|
16
|
+
type: :runtime
|
17
17
|
requirement: !ruby/object:Gem::Requirement
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
20
20
|
- !ruby/object:Gem::Version
|
21
21
|
version: '0'
|
22
22
|
none: false
|
23
|
-
type: :runtime
|
24
23
|
version_requirements: !ruby/object:Gem::Requirement
|
25
24
|
requirements:
|
26
25
|
- - ! '>='
|
27
26
|
- !ruby/object:Gem::Version
|
28
27
|
version: '0'
|
29
28
|
none: false
|
29
|
+
prerelease: false
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: addressable
|
32
|
-
|
32
|
+
type: :runtime
|
33
33
|
requirement: !ruby/object:Gem::Requirement
|
34
34
|
requirements:
|
35
35
|
- - ! '>='
|
36
36
|
- !ruby/object:Gem::Version
|
37
37
|
version: '0'
|
38
38
|
none: false
|
39
|
-
type: :runtime
|
40
39
|
version_requirements: !ruby/object:Gem::Requirement
|
41
40
|
requirements:
|
42
41
|
- - ! '>='
|
43
42
|
- !ruby/object:Gem::Version
|
44
43
|
version: '0'
|
45
44
|
none: false
|
45
|
+
prerelease: false
|
46
46
|
- !ruby/object:Gem::Dependency
|
47
47
|
name: nokogiri
|
48
|
-
|
48
|
+
type: :runtime
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
50
50
|
requirements:
|
51
51
|
- - ! '>='
|
52
52
|
- !ruby/object:Gem::Version
|
53
53
|
version: '0'
|
54
54
|
none: false
|
55
|
-
type: :runtime
|
56
55
|
version_requirements: !ruby/object:Gem::Requirement
|
57
56
|
requirements:
|
58
57
|
- - ! '>='
|
59
58
|
- !ruby/object:Gem::Version
|
60
59
|
version: '0'
|
61
60
|
none: false
|
61
|
+
prerelease: false
|
62
62
|
- !ruby/object:Gem::Dependency
|
63
63
|
name: json
|
64
|
-
|
64
|
+
type: :runtime
|
65
65
|
requirement: !ruby/object:Gem::Requirement
|
66
66
|
requirements:
|
67
67
|
- - ! '>='
|
68
68
|
- !ruby/object:Gem::Version
|
69
69
|
version: '0'
|
70
70
|
none: false
|
71
|
-
type: :runtime
|
72
71
|
version_requirements: !ruby/object:Gem::Requirement
|
73
72
|
requirements:
|
74
73
|
- - ! '>='
|
75
74
|
- !ruby/object:Gem::Version
|
76
75
|
version: '0'
|
77
76
|
none: false
|
77
|
+
prerelease: false
|
78
78
|
- !ruby/object:Gem::Dependency
|
79
79
|
name: rspec
|
80
|
-
|
80
|
+
type: :development
|
81
81
|
requirement: !ruby/object:Gem::Requirement
|
82
82
|
requirements:
|
83
83
|
- - ! '>='
|
84
84
|
- !ruby/object:Gem::Version
|
85
85
|
version: '0'
|
86
86
|
none: false
|
87
|
-
type: :development
|
88
87
|
version_requirements: !ruby/object:Gem::Requirement
|
89
88
|
requirements:
|
90
89
|
- - ! '>='
|
91
90
|
- !ruby/object:Gem::Version
|
92
91
|
version: '0'
|
93
92
|
none: false
|
93
|
+
prerelease: false
|
94
94
|
description: AWS SQS client
|
95
95
|
email: jemmyw@gmail.com
|
96
96
|
executables: []
|
@@ -99,6 +99,8 @@ extra_rdoc_files:
|
|
99
99
|
- README.rdoc
|
100
100
|
files:
|
101
101
|
- README.rdoc
|
102
|
+
- LICENSE
|
103
|
+
- CHANGELOG
|
102
104
|
- Rakefile
|
103
105
|
- lib/bisques/aws_connection.rb
|
104
106
|
- lib/bisques/aws_credentials.rb
|
@@ -122,17 +124,23 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
122
124
|
requirements:
|
123
125
|
- - ! '>='
|
124
126
|
- !ruby/object:Gem::Version
|
127
|
+
segments:
|
128
|
+
- 0
|
129
|
+
hash: -1167259765523084286
|
125
130
|
version: '0'
|
126
131
|
none: false
|
127
132
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
128
133
|
requirements:
|
129
134
|
- - ! '>='
|
130
135
|
- !ruby/object:Gem::Version
|
136
|
+
segments:
|
137
|
+
- 0
|
138
|
+
hash: -1167259765523084286
|
131
139
|
version: '0'
|
132
140
|
none: false
|
133
141
|
requirements: []
|
134
142
|
rubyforge_project:
|
135
|
-
rubygems_version: 1.8.
|
143
|
+
rubygems_version: 1.8.25
|
136
144
|
signing_key:
|
137
145
|
specification_version: 3
|
138
146
|
summary: AWS SQS client
|