bisques 1.0.1 → 1.0.2
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/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
|