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 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