queuel 0.4.1 → 0.4.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/Gemfile.lock +1 -1
- data/README.md +34 -12
- data/lib/queuel/sqs/message.rb +56 -37
- data/lib/queuel/sqs/queue.rb +2 -4
- data/lib/queuel/version.rb +1 -1
- data/spec/lib/queuel/sqs/message_spec.rb +31 -8
- data/spec/lib/queuel/sqs/queue_spec.rb +23 -0
- metadata +4 -4
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
Queuel
|
|
2
|
+
======
|
|
3
|
+
|
|
2
4
|
[](http://badge.fury.io/rb/queuel)
|
|
3
5
|
[](https://travis-ci.org/sportngin/queuel)
|
|
4
6
|
[](https://codeclimate.com/github/sportngin/queuel)
|
|
5
7
|
[](https://coveralls.io/r/sportngin/queuel)
|
|
6
8
|
|
|
7
|
-
Queuel is a kewl, lite wrapper around Queue interfaces. Currently it implements:
|
|
9
|
+
Queuel is a 'kewl', lite wrapper around Queue interfaces. Currently it implements:
|
|
8
10
|
|
|
9
11
|
* IronMQ
|
|
10
12
|
* Amazon SQS
|
|
@@ -18,7 +20,10 @@ Each of these should reliably implement:
|
|
|
18
20
|
|
|
19
21
|
Along with some further conveniences.
|
|
20
22
|
|
|
21
|
-
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
Installation
|
|
26
|
+
------------
|
|
22
27
|
|
|
23
28
|
Add this line to your application's Gemfile as well as the proper Gem for
|
|
24
29
|
your queuing:
|
|
@@ -31,7 +36,9 @@ gem 'queuel'
|
|
|
31
36
|
|
|
32
37
|
And then execute:
|
|
33
38
|
|
|
34
|
-
|
|
39
|
+
```bash
|
|
40
|
+
$ bundle
|
|
41
|
+
```
|
|
35
42
|
|
|
36
43
|
You will then want to configure:
|
|
37
44
|
|
|
@@ -43,7 +50,7 @@ Queuel.configure do
|
|
|
43
50
|
# requirement depends on your Queue
|
|
44
51
|
credentials token: 'asdufasdf8a7sd8fa7sdf', project_id: 'project_id'
|
|
45
52
|
|
|
46
|
-
# currently
|
|
53
|
+
# currently [:iron_mq, :sqs, :null] available
|
|
47
54
|
engine :iron_mq
|
|
48
55
|
|
|
49
56
|
# For Queuel.recevier {} you can configure more than one thread to
|
|
@@ -65,7 +72,10 @@ Queuel.configure do
|
|
|
65
72
|
end
|
|
66
73
|
```
|
|
67
74
|
|
|
68
|
-
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
Usage
|
|
78
|
+
-----
|
|
69
79
|
|
|
70
80
|
### General Queue API
|
|
71
81
|
|
|
@@ -90,15 +100,25 @@ Queuel.receive break_if_nil: true do |message|
|
|
|
90
100
|
end
|
|
91
101
|
```
|
|
92
102
|
|
|
93
|
-
Notes specific to the SQS engine:
|
|
94
|
-
A config should be added to provide `bucket_name`, `max_bytesize`, `access_key`
|
|
95
|
-
and `secret_access_key`. Without these, messages over the max_bytesize setting
|
|
96
|
-
(defaults to 64kb) will be dropped from the queue.
|
|
97
|
-
|
|
98
103
|
#### Caveats of the receiver
|
|
99
104
|
|
|
100
105
|
* Your block must return true in order to not replace the message to the Queue
|
|
101
106
|
|
|
107
|
+
#### SQS s3 fallback
|
|
108
|
+
|
|
109
|
+
Currently the SQS engine is the only engine with the s3 fallback support and
|
|
110
|
+
takes the following keys:
|
|
111
|
+
|
|
112
|
+
* `s3_access_key_id`
|
|
113
|
+
* `s3_secret_access_key`
|
|
114
|
+
* `s3_bucket_name`
|
|
115
|
+
* `max_bytesize` (optional)
|
|
116
|
+
|
|
117
|
+
With these in place, messages over the `max_bytesize` (defaults to 64kb) will
|
|
118
|
+
be sent to the designated bucket. Without this in place, messages over SQS's
|
|
119
|
+
limit be dropped from the queue.
|
|
120
|
+
|
|
121
|
+
|
|
102
122
|
### The message
|
|
103
123
|
|
|
104
124
|
```ruby
|
|
@@ -138,7 +158,9 @@ Queuel.receive decode: false
|
|
|
138
158
|
```
|
|
139
159
|
|
|
140
160
|
|
|
141
|
-
|
|
161
|
+
|
|
162
|
+
Contributing
|
|
163
|
+
------------
|
|
142
164
|
|
|
143
165
|
1. Fork it
|
|
144
166
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
data/lib/queuel/sqs/message.rb
CHANGED
|
@@ -1,80 +1,94 @@
|
|
|
1
1
|
module Queuel
|
|
2
2
|
module SQS
|
|
3
3
|
class Message < Base::Message
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
def raw_body
|
|
6
|
-
@raw_body ||= message_object
|
|
6
|
+
@raw_body ||= message_object ? pull_message : push_message
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
-
def
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
9
|
+
def delete
|
|
10
|
+
message_object.delete
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
[:id, :queue].each do |delegate|
|
|
14
|
+
define_method(delegate) do
|
|
15
|
+
instance_variable_get("@#{delegate}") || message_object && message_object.public_send(delegate)
|
|
16
|
+
end
|
|
16
17
|
end
|
|
17
18
|
|
|
18
19
|
def push_message
|
|
19
20
|
if encoded_body.bytesize > max_bytesize
|
|
20
21
|
key = generate_key
|
|
21
|
-
|
|
22
|
+
s3_transaction(:write, key, encoded_body)
|
|
22
23
|
self.body = { 'queuel_s3_object' => key }
|
|
23
24
|
end
|
|
24
25
|
encoded_body
|
|
25
26
|
end
|
|
27
|
+
private :push_message
|
|
26
28
|
|
|
27
29
|
def pull_message
|
|
28
30
|
begin
|
|
29
|
-
decoded_body =
|
|
30
|
-
if decoded_body.key?(
|
|
31
|
-
|
|
31
|
+
decoded_body = decoder.call(message_object.body)
|
|
32
|
+
if decoded_body.key?(:queuel_s3_object)
|
|
33
|
+
s3_transaction(:read, decoded_body[:queuel_s3_object])
|
|
32
34
|
else
|
|
33
35
|
message_object.body
|
|
34
36
|
end
|
|
35
|
-
rescue ::
|
|
37
|
+
rescue Queuel::Serialization::Json::SerializationError, TypeError
|
|
36
38
|
raw_body_with_sns_check
|
|
37
39
|
end
|
|
38
40
|
end
|
|
41
|
+
private :pull_message
|
|
39
42
|
|
|
40
43
|
def max_bytesize
|
|
41
44
|
options[:max_bytesize] || 64 * 1024
|
|
42
45
|
end
|
|
46
|
+
private :max_bytesize
|
|
43
47
|
|
|
44
|
-
def
|
|
45
|
-
@s3 ||= AWS::S3.new(
|
|
46
|
-
:access_key_id => options[:
|
|
47
|
-
:secret_access_key => options[:
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def read_from_s3 key
|
|
51
|
-
object = s3.buckets[options[:bucket_name]].objects[key]
|
|
52
|
-
object.read
|
|
48
|
+
def s3
|
|
49
|
+
@s3 ||= ::AWS::S3.new(
|
|
50
|
+
:access_key_id => options[:s3_access_key_id],
|
|
51
|
+
:secret_access_key => options[:s3_secret_access_key] )
|
|
53
52
|
end
|
|
53
|
+
private :s3
|
|
54
54
|
|
|
55
|
-
#
|
|
56
|
-
#
|
|
57
|
-
def
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
# @method - write or read
|
|
56
|
+
# @args - key and message if writing
|
|
57
|
+
def s3_transaction(method, *args)
|
|
58
|
+
bucket_name = options[:s3_bucket_name]
|
|
59
|
+
raise NoBucketNameSupplied if bucket_name.nil?
|
|
60
|
+
my_bucket = s3.buckets[bucket_name]
|
|
61
|
+
if my_bucket.exists?
|
|
62
|
+
begin
|
|
63
|
+
send("s3_#{method}", my_bucket, *args)
|
|
64
|
+
rescue AWS::S3::Errors::AccessDenied => e
|
|
65
|
+
raise InsufficientPermissions, "Unable to read from bucket: #{e.message}"
|
|
66
|
+
end
|
|
67
|
+
else
|
|
62
68
|
raise BucketDoesNotExistError, "Bucket has either expired or does not exist"
|
|
63
69
|
end
|
|
64
70
|
end
|
|
71
|
+
private :s3_transaction
|
|
65
72
|
|
|
66
|
-
|
|
73
|
+
def s3_read(bucket, *args)
|
|
74
|
+
bucket.objects[args[0]].read
|
|
67
75
|
end
|
|
76
|
+
private :s3_read
|
|
68
77
|
|
|
69
|
-
def
|
|
70
|
-
|
|
78
|
+
def s3_write(bucket, *args)
|
|
79
|
+
bucket.objects[args[0]].write(args[1])
|
|
71
80
|
end
|
|
81
|
+
private :s3_write
|
|
72
82
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
83
|
+
def generate_key
|
|
84
|
+
key = [
|
|
85
|
+
(Time.now.to_f * 10000).to_i,
|
|
86
|
+
SecureRandom.urlsafe_base64,
|
|
87
|
+
Thread.current.object_id
|
|
88
|
+
].join('-')
|
|
89
|
+
key
|
|
77
90
|
end
|
|
91
|
+
private :generate_key
|
|
78
92
|
|
|
79
93
|
def raw_body_with_sns_check
|
|
80
94
|
begin
|
|
@@ -84,6 +98,11 @@ module Queuel
|
|
|
84
98
|
end
|
|
85
99
|
end
|
|
86
100
|
private :raw_body_with_sns_check
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class NoBucketNameSupplied < Exception; end
|
|
104
|
+
class InsufficientPermissions < StandardError; end
|
|
105
|
+
class BucketDoesNotExistError < StandardError; end
|
|
87
106
|
end
|
|
88
107
|
end
|
|
89
108
|
end
|
data/lib/queuel/sqs/queue.rb
CHANGED
|
@@ -15,7 +15,8 @@ module Queuel
|
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
def push(message, options = {})
|
|
18
|
-
|
|
18
|
+
built_message = build_push_message message, options.merge(credentials)
|
|
19
|
+
queue_connection.send_message built_message
|
|
19
20
|
end
|
|
20
21
|
|
|
21
22
|
def approximate_number_of_messages
|
|
@@ -28,17 +29,14 @@ module Queuel
|
|
|
28
29
|
|
|
29
30
|
private
|
|
30
31
|
|
|
31
|
-
|
|
32
32
|
def build_new_message(bare_message, options = {})
|
|
33
33
|
message_klass.new(bare_message, credentials)
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
-
|
|
37
36
|
def pop_bare_message(options = {})
|
|
38
37
|
queue_connection.receive_message options
|
|
39
38
|
end
|
|
40
39
|
|
|
41
|
-
|
|
42
40
|
def queue_connection
|
|
43
41
|
@queue_connection ||= client.queues.named(name)
|
|
44
42
|
end
|
data/lib/queuel/version.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
require 'json'
|
|
3
|
+
require 'aws-sdk'
|
|
3
4
|
module Queuel
|
|
4
5
|
module SQS
|
|
5
6
|
describe Message do
|
|
@@ -20,26 +21,48 @@ module Queuel
|
|
|
20
21
|
its(:body) { should == "body" }
|
|
21
22
|
its(:queue) { should == queue_double }
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
it "calls raw_body_with_sns_check if not a json object" do
|
|
25
|
+
subject.should_receive(:raw_body_with_sns_check)
|
|
26
|
+
subject.raw_body
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
context "when pulling an oversized message" do
|
|
30
|
+
let(:body) { '{"queuel_s3_object": "whatever"}' }
|
|
31
|
+
let(:message_object) { double "SQSMessage", id: 2, body: body, queue: queue_double }
|
|
32
|
+
subject { described_class.new(message_object) }
|
|
25
33
|
|
|
26
|
-
it "
|
|
27
|
-
subject.should_receive(:
|
|
34
|
+
it "calls s3_transaction with read" do
|
|
35
|
+
subject.should_receive(:s3_transaction).with(:read, "whatever")
|
|
28
36
|
subject.raw_body
|
|
29
37
|
end
|
|
30
38
|
end
|
|
31
39
|
|
|
32
|
-
|
|
40
|
+
context "when pushing an oversized json hash" do
|
|
41
|
+
let(:message) { double("body", bytesize: subject.send(:max_bytesize) + 1) }
|
|
33
42
|
before do
|
|
34
43
|
subject.send("message_object=", nil)
|
|
35
|
-
subject.stub(:encoded_body).and_return
|
|
44
|
+
subject.stub(:encoded_body).and_return message
|
|
36
45
|
end
|
|
37
|
-
|
|
38
|
-
|
|
46
|
+
|
|
47
|
+
it "should call s3_transaction with write" do
|
|
48
|
+
subject.stub(:generate_key).and_return "key"
|
|
49
|
+
subject.should_receive(:s3_transaction).with(:write, "key", message)
|
|
39
50
|
subject.raw_body
|
|
40
51
|
end
|
|
41
52
|
end
|
|
42
53
|
|
|
54
|
+
describe "#s3" do
|
|
55
|
+
subject do
|
|
56
|
+
described_class.new message_object, :s3_access_key_id => "stuff",
|
|
57
|
+
:s3_secret_access_key => "derp"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "sets the s3 object" do
|
|
61
|
+
AWS::S3.should_receive(:new).with(:access_key_id => "stuff", :secret_access_key => "derp")
|
|
62
|
+
subject.send :s3
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
43
66
|
describe "with json" do
|
|
44
67
|
let(:body) { '{"username":"jon"}' }
|
|
45
68
|
before do
|
|
@@ -26,6 +26,29 @@ module Queuel
|
|
|
26
26
|
subject.size
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
|
+
|
|
30
|
+
describe "push" do
|
|
31
|
+
before do
|
|
32
|
+
queue_object_with_message.should_receive(:send_message)
|
|
33
|
+
.with('foobar')
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "receives a call to build message with the credentials" do
|
|
37
|
+
subject.should_receive(:build_push_message)
|
|
38
|
+
.with("foobar", credentials)
|
|
39
|
+
.and_return('foobar')
|
|
40
|
+
|
|
41
|
+
subject.push "foobar"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "merges options that are passed in" do
|
|
45
|
+
subject.should_receive(:build_push_message)
|
|
46
|
+
.with("foobar", {:foo => 'bar'}.merge(credentials))
|
|
47
|
+
.and_return('foobar')
|
|
48
|
+
|
|
49
|
+
subject.push "foobar", :foo => 'bar'
|
|
50
|
+
end
|
|
51
|
+
end
|
|
29
52
|
end
|
|
30
53
|
end
|
|
31
54
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: queuel
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.4.
|
|
4
|
+
version: 0.4.2
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2014-04-
|
|
12
|
+
date: 2014-04-22 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: bundler
|
|
@@ -403,7 +403,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
403
403
|
version: '0'
|
|
404
404
|
segments:
|
|
405
405
|
- 0
|
|
406
|
-
hash:
|
|
406
|
+
hash: 2118927277156940265
|
|
407
407
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
408
408
|
none: false
|
|
409
409
|
requirements:
|
|
@@ -412,7 +412,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
412
412
|
version: '0'
|
|
413
413
|
segments:
|
|
414
414
|
- 0
|
|
415
|
-
hash:
|
|
415
|
+
hash: 2118927277156940265
|
|
416
416
|
requirements: []
|
|
417
417
|
rubyforge_project:
|
|
418
418
|
rubygems_version: 1.8.23.2
|