queuel 0.4.1 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- queuel (0.4.1)
4
+ queuel (0.4.2)
5
5
  mono_logger
6
6
  multi_json
7
7
  thread
data/README.md CHANGED
@@ -1,10 +1,12 @@
1
- # Queuel
1
+ Queuel
2
+ ======
3
+
2
4
  [![Gem Version](https://badge.fury.io/rb/queuel.png)](http://badge.fury.io/rb/queuel)
3
5
  [![Build Status](https://travis-ci.org/sportngin/queuel.png?branch=master)](https://travis-ci.org/sportngin/queuel)
4
6
  [![Code Climate](https://codeclimate.com/github/sportngin/queuel.png)](https://codeclimate.com/github/sportngin/queuel)
5
7
  [![Coverage Status](https://coveralls.io/repos/sportngin/queuel/badge.png)](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
- ## Installation
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
- $ bundle
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 only [:iron_mq, :null] available
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
- ## Usage
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
- ## Contributing
161
+
162
+ Contributing
163
+ ------------
142
164
 
143
165
  1. Fork it
144
166
  2. Create your feature branch (`git checkout -b my-new-feature`)
@@ -1,80 +1,94 @@
1
1
  module Queuel
2
2
  module SQS
3
3
  class Message < Base::Message
4
- # if message_object exists (not nil), receive the data, otherwise push
4
+
5
5
  def raw_body
6
- @raw_body ||= message_object.nil? ? push_message : pull_message
6
+ @raw_body ||= message_object ? pull_message : push_message
7
7
  end
8
8
 
9
- def generate_key
10
- key = [
11
- (Time.now.to_f * 10000).to_i,
12
- SecureRandom.urlsafe_base64,
13
- Thread.current.object_id
14
- ].join('-')
15
- key
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
- write_to_s3(encoded_body, key)
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 = JSON.parse(message_object.body)
30
- if decoded_body.key?('queuel_s3_object')
31
- read_from_s3 decoded_body[:queuel_s3_object]
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 ::JSON::ParserError, TypeError
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 self.s3
45
- @s3 ||= AWS::S3.new(
46
- :access_key_id => options[:access_token],
47
- :secret_access_key => options[:secret_access_token] )
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
- # this assumes you've set up some rules for file expiration on your
56
- # configured bucket.
57
- def write_to_s3(message, key)
58
- begin
59
- my_bucket = s3.buckets[options[:bucket_name]]
60
- my_bucket.objects[key].write(message)
61
- rescue
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
- class BucketDoesNotExistError < StandardError
73
+ def s3_read(bucket, *args)
74
+ bucket.objects[args[0]].read
67
75
  end
76
+ private :s3_read
68
77
 
69
- def delete
70
- message_object.delete
78
+ def s3_write(bucket, *args)
79
+ bucket.objects[args[0]].write(args[1])
71
80
  end
81
+ private :s3_write
72
82
 
73
- [:id, :queue].each do |delegate|
74
- define_method(delegate) do
75
- instance_variable_get("@#{delegate}") || message_object && message_object.public_send(delegate)
76
- end
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
@@ -15,7 +15,8 @@ module Queuel
15
15
 
16
16
 
17
17
  def push(message, options = {})
18
- queue_connection.send_message build_push_message(message, options)
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
@@ -1,3 +1,3 @@
1
1
  module Queuel
2
- VERSION = "0.4.1"
2
+ VERSION = "0.4.2"
3
3
  end
@@ -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
- describe "when pulling an oversized message" do
24
- let(:body) { '{"queuel_s3_object": "whatever" }' }
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 "should call read_from_s3" do
27
- subject.should_receive(:read_from_s3)
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
- describe "when pushing an oversized json hash" do
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 double("body", bytesize: subject.max_bytesize+1)
44
+ subject.stub(:encoded_body).and_return message
36
45
  end
37
- it "should call write_to_s3" do
38
- subject.should_receive(:write_to_s3)
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.1
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-08 00:00:00.000000000 Z
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: -3766388311581194323
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: -3766388311581194323
415
+ hash: 2118927277156940265
416
416
  requirements: []
417
417
  rubyforge_project:
418
418
  rubygems_version: 1.8.23.2