pauldowman-sqs_accelerator 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +80 -0
- data/lib/server.rb +166 -0
- data/lib/sqs_accelerator.rb +2 -0
- data/lib/sqs_helper.rb +63 -0
- data/lib/sqs_proxy.rb +27 -0
- data/sqs_accelerator.gemspec +30 -0
- data/sqs_accelerator.ru +5 -0
- data/views/all_queues.haml +13 -0
- data/views/home.haml +26 -0
- data/views/queue_info.haml +31 -0
- metadata +111 -0
data/README.markdown
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
SQS Accelerator
|
2
|
+
===============
|
3
|
+
|
4
|
+
[http://github.com/pauldowman/sqs_accelerator](http://github.com/pauldowman/sqs_accelerator)
|
5
|
+
|
6
|
+
_WARNING: this is totally experimental right now! It's just an idea I'm playing with and I'm trying to see if it works. (But please try it out and tell me what you think!)_
|
7
|
+
|
8
|
+
This is a simple and scalable event-driven server (using [Event Machine](http://eventmachine.rubyforge.org)) that proxies requests to Amazon's [Simple Queue Service](http://aws.amazon.com/sqs/) hosted queue. It's purpose is to queue messages very quickly, because otherwise SQS is too slow to use from within a web app (to be precise, the time it takes to queue a message is often too long).
|
9
|
+
|
10
|
+
It provides a simple RESTful interface for interacting with SQS that's also convenient to use from a browser.
|
11
|
+
|
12
|
+
One instance of the SQS Accelerator can send messages to any number of SQS queues, the queue name is given in the URL and the AWS credentials are given in HTTP headers (as HTTP Basic Authentication headers actually so it's convenient to use from a browser)
|
13
|
+
|
14
|
+
|
15
|
+
How it works
|
16
|
+
------------
|
17
|
+
|
18
|
+
The SQS Accelerator accepts messages from your web app and returns a response instantly without waiting for a response from SQS. Your web app then happily continues and returns it's response to the user. The SQS Accelerator finishes queueing the message to SQS in the background.
|
19
|
+
|
20
|
+
It runs as a daemon, if it's accepting queued messages from a web app one instance should be run on each app server. It listens on port 9292.
|
21
|
+
|
22
|
+
|
23
|
+
FAQ
|
24
|
+
------
|
25
|
+
|
26
|
+
__Q: Won't lots of messages build up inside SQS Accelerator since it receives them faster than it sends them to SQS?__
|
27
|
+
|
28
|
+
A: No, but you might get errors if you hit the maximum number of open connections (not sure what this limit is yet, but it should be very high with EventMachine). SQS has high latency, but it can accept a virtually unlimited number of incoming connections, so if you can hold a large number of open connections to it then your throughput can be very high. Because an evented client can hold a large number of open connections it can maintain a very high throughput.
|
29
|
+
|
30
|
+
__Q: Isn't this like queueing messages locally before queueing them in SQS?__
|
31
|
+
|
32
|
+
A: No, it's more like a proxy than a queue, the messages don't build up inside SQS Accelerator, they are all being sent to SQS concurrently.
|
33
|
+
|
34
|
+
__Q: Why not just use a local queue?__
|
35
|
+
|
36
|
+
A: You could do that instead of using SQS. But SQS is simple and scalable, and it's also simple and scalable to run an instance of SQS Accelerator on each app server.
|
37
|
+
|
38
|
+
__Q: Are you sure about all this?__
|
39
|
+
|
40
|
+
A: Not yet, it's just a theory so far, my next priority is to benchmark this and make sure it really works as it should in theory.
|
41
|
+
|
42
|
+
|
43
|
+
Usage instructions
|
44
|
+
------------------
|
45
|
+
|
46
|
+
* Install this gem
|
47
|
+
* Run sqs_accelerator.ru
|
48
|
+
* Hit [http://localhost:9292/](http://localhost:9292/) in a browser
|
49
|
+
* Make an HTTP GET request to /queues to list all queues
|
50
|
+
* Make an HTTP POST request to /queues with queue_name=newqueue to create a queue named newqueue
|
51
|
+
* Make an HTTP GET request to /queues/queuename to show info about a queue named "queuename" and to give a form to send a message
|
52
|
+
* Make an HTTP POST request to /queues/queuename to send a message
|
53
|
+
* Use your SQS credentials for HTTP auth
|
54
|
+
* TODO improve these instructions
|
55
|
+
|
56
|
+
|
57
|
+
Thanks to the following great projects
|
58
|
+
--------------------------------------
|
59
|
+
|
60
|
+
* [Event Machine](http://eventmachine.rubyforge.org), the thing that makes this even possible.
|
61
|
+
* [async_sinatra](http://github.com/raggi/async_sinatra), allows writing evented HTTP servers using the nice Sinatra framework/DSL.
|
62
|
+
* [em-http-request](http://github.com/igrigorik/em-http-request), an asynchronous HTTP Client.
|
63
|
+
* [RightAWS](http://rightscale.rubyforge.org/right_aws_gem_doc) (I stole a few lines of the SQS code).
|
64
|
+
* [Amazon SQS](http://aws.amazon.com/sqs/) for having a decent [Query API](http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/), even if it's not actually RESTful. :-)
|
65
|
+
|
66
|
+
|
67
|
+
Still to do
|
68
|
+
-----
|
69
|
+
|
70
|
+
* Find all the TODO comments in the code
|
71
|
+
* Benchmarking
|
72
|
+
* A command to start and stop the daemon, maybe a [god](http://god.rubyforge.org/) config file
|
73
|
+
* Use SSL when connecting to SQS to protect message content (AWS credentials are never sent, they're just used to sign the message)
|
74
|
+
* Unit tests (I'm just trying to figure out if this idea even works first)
|
75
|
+
* Create a Ruby client library
|
76
|
+
* Switch all actions to use evented HTTP client instead of EM.defer. Right now some actions are using EM.defer to use the RightAWS client in a thread. These actions will be less scalable. Sending messages, the most important action, _is_ using the evented client. This means making direct HTTP requests to the [SQS Query API](http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/)
|
77
|
+
* Fix bugs and make it nicer.
|
78
|
+
* Refactor all the SQS stuff out of the actions
|
79
|
+
* Some configuration options
|
80
|
+
|
data/lib/server.rb
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
require "em-http"
|
2
|
+
require "haml"
|
3
|
+
require "logger"
|
4
|
+
require "pp"
|
5
|
+
require "sinatra/async"
|
6
|
+
require "xml"
|
7
|
+
|
8
|
+
require "#{File.dirname(__FILE__)}/sqs_accelerator"
|
9
|
+
require "#{File.dirname(__FILE__)}/sqs_helper"
|
10
|
+
require "#{File.dirname(__FILE__)}/sqs_proxy"
|
11
|
+
|
12
|
+
class SqsAccelerator::Server < Sinatra::Base
|
13
|
+
register Sinatra::Async
|
14
|
+
|
15
|
+
configure do
|
16
|
+
# TODO fix logging.
|
17
|
+
LOGGER = Logger.new(STDOUT)
|
18
|
+
LOGGER.level = Logger::DEBUG
|
19
|
+
use Rack::CommonLogger, LOGGER
|
20
|
+
end
|
21
|
+
|
22
|
+
# use http basic auth to get aws_access_key_id and aws_secret_access_key
|
23
|
+
helpers do
|
24
|
+
include SqsAccelerator::SqsHelper
|
25
|
+
|
26
|
+
def deny
|
27
|
+
response['WWW-Authenticate'] = %(Basic realm="SQS Accelerator - use SQS credentials")
|
28
|
+
response.status = 401 # "Unauthorized": http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
|
29
|
+
body "Please provide the SQS access key id and secret access key as the userid and password.\n"
|
30
|
+
end
|
31
|
+
|
32
|
+
def authorized?
|
33
|
+
@auth ||= Rack::Auth::Basic::Request.new(request.env)
|
34
|
+
@auth.provided? && @auth.basic? && @auth.credentials
|
35
|
+
# We don't care what the credentials are, we'll just pass them on to SQS
|
36
|
+
end
|
37
|
+
|
38
|
+
def aws_access_key_id
|
39
|
+
@auth.credentials[0]
|
40
|
+
end
|
41
|
+
|
42
|
+
def aws_secret_access_key
|
43
|
+
@auth.credentials[1]
|
44
|
+
end
|
45
|
+
|
46
|
+
def logger
|
47
|
+
LOGGER
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
aget '/' do
|
52
|
+
body haml :home
|
53
|
+
end
|
54
|
+
|
55
|
+
aget '/queues' do
|
56
|
+
deny and return unless authorized?
|
57
|
+
|
58
|
+
request_hash = generate_request_hash('ListQueues')
|
59
|
+
http = EventMachine::HttpRequest.new("http://queue.amazonaws.com/").get :query => request_hash, :timeout => 120
|
60
|
+
|
61
|
+
http.callback {
|
62
|
+
queue_urls = []
|
63
|
+
doc = parse_response(http.response)
|
64
|
+
doc.find('//sqs:QueueUrl').each do |u|
|
65
|
+
queue_urls << u.content.strip
|
66
|
+
end
|
67
|
+
|
68
|
+
body haml :all_queues, :locals => { :queue_urls => queue_urls }
|
69
|
+
}
|
70
|
+
|
71
|
+
http.errback {
|
72
|
+
# TODO a decent log message and error page here
|
73
|
+
logger.debug "fail"
|
74
|
+
body "fail"
|
75
|
+
}
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
# Create a queue
|
80
|
+
apost '/queues' do
|
81
|
+
deny and return unless authorized?
|
82
|
+
|
83
|
+
queue_name = params[:queue_name]
|
84
|
+
visibility_timeout = params[:visibility_timeout]
|
85
|
+
|
86
|
+
# TODO switch to using evented client
|
87
|
+
operation = proc do
|
88
|
+
sqs = SqsAccelerator::SqsProxy.new(aws_access_key_id, aws_secret_access_key, :logger => logger)
|
89
|
+
sqs.create_queue(queue_name, visibility_timeout)
|
90
|
+
# TODO check the result and return an error unless success
|
91
|
+
# TODO set Location header field with URI
|
92
|
+
response.status = 201 # "Created": http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
|
93
|
+
body haml :queue_created, :locals => { :queue_name => queue_name }
|
94
|
+
end
|
95
|
+
EM.defer(operation)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Get info on a queue. Doesn't create the queue if it doesn't exist
|
99
|
+
aget '/queues/:queue_name' do
|
100
|
+
deny and return unless authorized?
|
101
|
+
|
102
|
+
queue_name = params[:queue_name]
|
103
|
+
|
104
|
+
# TODO switch to using evented client
|
105
|
+
operation = proc do
|
106
|
+
sqs = SqsAccelerator::SqsProxy.new(aws_access_key_id, aws_secret_access_key, :logger => logger)
|
107
|
+
queue_info = sqs.get_queue_info(queue_name)
|
108
|
+
body haml :queue_info, :locals => { :queue_name => queue_name, :queue_info => queue_info }
|
109
|
+
end
|
110
|
+
EM.defer(operation)
|
111
|
+
end
|
112
|
+
|
113
|
+
# Send a new message on a queue. Returns immediately and sends message asynchronously
|
114
|
+
apost '/queues/:queue_name' do
|
115
|
+
deny and return unless authorized?
|
116
|
+
|
117
|
+
queue_name = params[:queue_name]
|
118
|
+
message_body = params[:message_body]
|
119
|
+
|
120
|
+
logger.info "Received message for queue #{queue_name}"
|
121
|
+
logger.debug "message_body: #{message_body}"
|
122
|
+
|
123
|
+
# TODO check that chars are allowed by SQS: #x9 | #xA | #xD | [#x20 to #xD7FF] | [#xE000 to #xFFFD] | [#x10000 to #x10FFFF]
|
124
|
+
# TODO deal with unicode, where chars != bytes
|
125
|
+
if message_body.size > SqsAccelerator::SqsHelper::MAX_MESSAGE_SIZE
|
126
|
+
logger.error "Message is too large, rejecting."
|
127
|
+
response.status = 413 # "Request Entity Too Large": http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
|
128
|
+
body "Message must be less than SqsAccelerator::SqsHelper::MAX_MESSAGE_SIZE bytes"
|
129
|
+
return
|
130
|
+
end
|
131
|
+
|
132
|
+
# Messaage seems to be OK, return a response immediately then send message to SQS
|
133
|
+
response.status = 202 # "Accepted": http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
|
134
|
+
body "Message will be queued, check log for errors.\n"
|
135
|
+
# TODO generate and return a message id then log that with the SQS message id?
|
136
|
+
|
137
|
+
request_hash = generate_request_hash("SendMessage", :message => message_body)
|
138
|
+
# build the body string ourselves for now until Ilya's gem gets updated because of the content-length bug
|
139
|
+
request_body = request_hash.to_a.collect{|key,val| CGI.escape(key.to_s) + "=" + CGI.escape(val.to_s) }.join("&")
|
140
|
+
http = EventMachine::HttpRequest.new("http://queue.amazonaws.com/#{queue_name}").post({:body => request_body, :head => {"Content-Type" => "application/x-www-form-urlencoded"}})
|
141
|
+
|
142
|
+
http.callback {
|
143
|
+
doc = parse_response(http.response)
|
144
|
+
id_el = doc.find_first('//sqs:MessageId')
|
145
|
+
md5_el = doc.find_first('//sqs:MD5OfMessageBody')
|
146
|
+
if id_el && md5_el
|
147
|
+
message_id = id_el.content.strip
|
148
|
+
checksum = md5_el.content.strip
|
149
|
+
# TODO check md5
|
150
|
+
# TODO a decent log message here
|
151
|
+
logger.info "Queued message, SQS message id is: #{message_id}"
|
152
|
+
else
|
153
|
+
logger.error "SQS returned an error response"
|
154
|
+
# TODO parse the response and print something useful
|
155
|
+
# TODO retry a few times with exponentially increasing delay
|
156
|
+
end
|
157
|
+
}
|
158
|
+
|
159
|
+
http.errback {
|
160
|
+
# TODO a decent log message here
|
161
|
+
logger.error "fail"
|
162
|
+
# TODO dump the message to a temp file and write a utility to re-send dumped messages
|
163
|
+
}
|
164
|
+
|
165
|
+
end
|
166
|
+
end
|
data/lib/sqs_helper.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require "cgi"
|
2
|
+
require "base64"
|
3
|
+
require "rexml/document"
|
4
|
+
require "openssl"
|
5
|
+
require "digest/sha1"
|
6
|
+
require 'md5'
|
7
|
+
|
8
|
+
module SqsAccelerator::SqsHelper
|
9
|
+
# Thanks to RightScale for the great RightAWS library.
|
10
|
+
# Parts of this code have been inspired by/stolen from RightAws.
|
11
|
+
|
12
|
+
SIGNATURE_VERSION = "1"
|
13
|
+
API_VERSION = "2008-01-01"
|
14
|
+
DEFAULT_HOST = "queue.amazonaws.com"
|
15
|
+
DEFAULT_PORT = 80
|
16
|
+
DEFAULT_PROTOCOL = 'http'
|
17
|
+
REQUEST_TTL = 30
|
18
|
+
DEFAULT_VISIBILITY_TIMEOUT = 30
|
19
|
+
MAX_MESSAGE_SIZE = (8 * 1024)
|
20
|
+
|
21
|
+
@@digest = OpenSSL::Digest::Digest.new("sha1")
|
22
|
+
|
23
|
+
def sign(aws_secret_access_key, auth_string)
|
24
|
+
Base64.encode64(OpenSSL::HMAC.digest(@@digest, aws_secret_access_key, auth_string)).strip
|
25
|
+
end
|
26
|
+
|
27
|
+
# From Amazon's SQS Dev Guide, a brief description of how to escape:
|
28
|
+
# "URL encode the computed signature and other query parameters as specified in
|
29
|
+
# RFC1738, section 2.2. In addition, because the + character is interpreted as a blank space
|
30
|
+
# by Sun Java classes that perform URL decoding, make sure to encode the + character
|
31
|
+
# although it is not required by RFC1738."
|
32
|
+
# Avoid using CGI::escape to escape URIs.
|
33
|
+
# CGI::escape will escape characters in the protocol, host, and port
|
34
|
+
# sections of the URI. Only target chars in the query
|
35
|
+
# string should be escaped.
|
36
|
+
def URLencode(raw)
|
37
|
+
e = URI.escape(raw)
|
38
|
+
e.gsub(/\+/, "%2b")
|
39
|
+
end
|
40
|
+
|
41
|
+
def generate_request_hash(action, params={})
|
42
|
+
message = params[:message]
|
43
|
+
params.each{ |key, value| params.delete(key) if (value.nil? || key.is_a?(Symbol)) }
|
44
|
+
request_hash = { "Action" => action,
|
45
|
+
"Expires" => (Time.now + REQUEST_TTL).utc.strftime("%Y-%m-%dT%H:%M:%SZ"),
|
46
|
+
"AWSAccessKeyId" => aws_access_key_id,
|
47
|
+
"Version" => API_VERSION,
|
48
|
+
"SignatureVersion" => SIGNATURE_VERSION }
|
49
|
+
request_hash["MessageBody"] = message if message
|
50
|
+
request_hash.merge(params)
|
51
|
+
request_data = request_hash.sort{|a,b| (a[0].to_s.downcase)<=>(b[0].to_s.downcase)}.to_s
|
52
|
+
request_hash['Signature'] = sign(aws_secret_access_key, request_data)
|
53
|
+
logger.debug "request_hash:\n#{request_hash.pretty_inspect}"
|
54
|
+
return request_hash
|
55
|
+
end
|
56
|
+
|
57
|
+
def parse_response(string)
|
58
|
+
parser = XML::Parser.string(string)
|
59
|
+
doc = parser.parse
|
60
|
+
doc.root.namespaces.default_prefix = "sqs"
|
61
|
+
return doc
|
62
|
+
end
|
63
|
+
end
|
data/lib/sqs_proxy.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require "right_aws"
|
2
|
+
|
3
|
+
# This class will be removed. It's just for the operations that haven't been
|
4
|
+
# switched to use the evented http client yet.
|
5
|
+
|
6
|
+
class SqsAccelerator::SqsProxy
|
7
|
+
|
8
|
+
def initialize(aws_access_key_id, aws_secret_access_key, options = {})
|
9
|
+
options = {:multi_thread => true}.merge(options)
|
10
|
+
@logger = options[:logger]
|
11
|
+
@sqs = RightAws::SqsGen2.new(aws_access_key_id, aws_secret_access_key, options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def create_queue(queue_name, visibility_timeout)
|
15
|
+
RightAws::SqsGen2::Queue.create(@sqs, queue_name, true, visibility_timeout)
|
16
|
+
end
|
17
|
+
|
18
|
+
def get_queue_info(queue_name)
|
19
|
+
# TODO do something smart if the queue doesn't exist
|
20
|
+
queue = @sqs.queue(queue_name, false)
|
21
|
+
queue_info = {
|
22
|
+
:num_messages => queue.size,
|
23
|
+
:visibility_timeout => queue.visibility
|
24
|
+
}
|
25
|
+
return queue_info
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
spec = Gem::Specification.new do |s|
|
2
|
+
s.name = 'sqs_accelerator'
|
3
|
+
s.version = '0.0.1'
|
4
|
+
s.date = '2009-06-22'
|
5
|
+
s.summary = 'SQS Accelerator'
|
6
|
+
s.description = "A simple and scalable event-drive server that proxies requests to Amazon's Simple Queue Service to queue messages very quickly."
|
7
|
+
s.email = 'paul@pauldowman.com'
|
8
|
+
s.homepage = "http://github.com/pauldowman/sqs-accelerator"
|
9
|
+
s.has_rdoc = false
|
10
|
+
s.authors = ["Paul Dowman"]
|
11
|
+
s.add_dependency('eventmachine', '>= 0.12.2')
|
12
|
+
s.add_dependency('igrigorik-em-http-request', '>= 0.1.6')
|
13
|
+
s.add_dependency('sinatra', '>= 0.9.2')
|
14
|
+
s.add_dependency('async_sinatra', '>= 0.1.4')
|
15
|
+
s.add_dependency('libxml-ruby', '>= 1.1.3')
|
16
|
+
s.rubyforge_project = "sqs-accelerator"
|
17
|
+
|
18
|
+
# ruby -rpp -e' pp `git ls-files`.split("\n") '
|
19
|
+
s.files = ["README.markdown",
|
20
|
+
"lib/server.rb",
|
21
|
+
"lib/sqs_accelerator.rb",
|
22
|
+
"lib/sqs_helper.rb",
|
23
|
+
"lib/sqs_proxy.rb",
|
24
|
+
"sqs_accelerator.gemspec",
|
25
|
+
"sqs_accelerator.ru",
|
26
|
+
"views/all_queues.haml",
|
27
|
+
"views/home.haml",
|
28
|
+
"views/queue_info.haml"]
|
29
|
+
|
30
|
+
end
|
data/sqs_accelerator.ru
ADDED
data/views/home.haml
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
!!! XML
|
2
|
+
!!!
|
3
|
+
%html{:xmlns => "http://www.w3.org/1999/xhtml", 'xml:lang' => "en", :lang => "en"}
|
4
|
+
%head
|
5
|
+
%title
|
6
|
+
SQS Accelerator
|
7
|
+
%body
|
8
|
+
%h3
|
9
|
+
SQS Accelerator
|
10
|
+
|
11
|
+
%p
|
12
|
+
TODO more detail and links here
|
13
|
+
%ul
|
14
|
+
%li
|
15
|
+
Make an HTTP GET request to
|
16
|
+
%a{:href => "/queues"}
|
17
|
+
\/queues
|
18
|
+
to list all queues
|
19
|
+
%li
|
20
|
+
Make an HTTP POST request to /queues with queue_name=newqueue to create a queue named newqueue
|
21
|
+
%li
|
22
|
+
Make an HTTP GET request to /queues/queuename to show info about a queue named "queuename" and to give a form to send a message
|
23
|
+
%li
|
24
|
+
Make an HTTP POST request to /queues/queuename to send a message
|
25
|
+
%li
|
26
|
+
Use your SQS credentials for HTTP auth
|
@@ -0,0 +1,31 @@
|
|
1
|
+
!!! XML
|
2
|
+
!!!
|
3
|
+
%html{:xmlns => "http://www.w3.org/1999/xhtml", 'xml:lang' => "en", :lang => "en"}
|
4
|
+
%head
|
5
|
+
%title
|
6
|
+
SQS Queue name:
|
7
|
+
= queue_name
|
8
|
+
%body
|
9
|
+
%h3
|
10
|
+
SQS Queue name:
|
11
|
+
= queue_name
|
12
|
+
|
13
|
+
%p
|
14
|
+
Approximate number of messages in queue:
|
15
|
+
= queue_info[:num_messages]
|
16
|
+
|
17
|
+
%p
|
18
|
+
Visibility timeout:
|
19
|
+
= queue_info[:visibility_timeout]
|
20
|
+
|
21
|
+
%p
|
22
|
+
Queue a new message:
|
23
|
+
%form{:method => "POST"}
|
24
|
+
%p
|
25
|
+
Send message:
|
26
|
+
%br/
|
27
|
+
%textarea{:name => "message_body", :cols => "80", :rows => "20"}
|
28
|
+
|
29
|
+
%p
|
30
|
+
%input{:type => "submit"}
|
31
|
+
|
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pauldowman-sqs_accelerator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Paul Dowman
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-06-22 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: eventmachine
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.12.2
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: igrigorik-em-http-request
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.1.6
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: sinatra
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.9.2
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: async_sinatra
|
47
|
+
type: :runtime
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.1.4
|
54
|
+
version:
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: libxml-ruby
|
57
|
+
type: :runtime
|
58
|
+
version_requirement:
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 1.1.3
|
64
|
+
version:
|
65
|
+
description: A simple and scalable event-drive server that proxies requests to Amazon's Simple Queue Service to queue messages very quickly.
|
66
|
+
email: paul@pauldowman.com
|
67
|
+
executables: []
|
68
|
+
|
69
|
+
extensions: []
|
70
|
+
|
71
|
+
extra_rdoc_files: []
|
72
|
+
|
73
|
+
files:
|
74
|
+
- README.markdown
|
75
|
+
- lib/server.rb
|
76
|
+
- lib/sqs_accelerator.rb
|
77
|
+
- lib/sqs_helper.rb
|
78
|
+
- lib/sqs_proxy.rb
|
79
|
+
- sqs_accelerator.gemspec
|
80
|
+
- sqs_accelerator.ru
|
81
|
+
- views/all_queues.haml
|
82
|
+
- views/home.haml
|
83
|
+
- views/queue_info.haml
|
84
|
+
has_rdoc: false
|
85
|
+
homepage: http://github.com/pauldowman/sqs-accelerator
|
86
|
+
post_install_message:
|
87
|
+
rdoc_options: []
|
88
|
+
|
89
|
+
require_paths:
|
90
|
+
- lib
|
91
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: "0"
|
96
|
+
version:
|
97
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: "0"
|
102
|
+
version:
|
103
|
+
requirements: []
|
104
|
+
|
105
|
+
rubyforge_project: sqs-accelerator
|
106
|
+
rubygems_version: 1.2.0
|
107
|
+
signing_key:
|
108
|
+
specification_version: 2
|
109
|
+
summary: SQS Accelerator
|
110
|
+
test_files: []
|
111
|
+
|