qsagi 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/qsagi.rb +2 -0
- data/lib/qsagi/confirmed_queue.rb +66 -0
- data/lib/qsagi/message.rb +4 -8
- data/lib/qsagi/queue.rb +36 -49
- data/lib/qsagi/standard_queue.rb +70 -0
- data/lib/qsagi/version.rb +1 -1
- data/qsagi.gemspec +1 -1
- data/spec/qsagi/confirmed_queue_spec.rb +33 -0
- data/spec/qsagi/message_spec.rb +5 -23
- data/spec/qsagi/queue_spec.rb +35 -1
- data/spec/spec_helper.rb +4 -5
- metadata +13 -15
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5abc20946ce817158e4ccbcd23c4297457dfa967
|
4
|
+
data.tar.gz: b454ffe9a3616b7796f6c4b83d6b7f003b8fe8da
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4c29980ce4a2bb9bfb1a069731f6568c3f09354d3da65499fee67cd08bfa487e7f8504eb7447103a0f46e3d04c958722e5d7e75f708fa9181b7b95a6fb6bbe28
|
7
|
+
data.tar.gz: 4d9dad24f276baec8bd09c2b2d5c9ba19cc25538b452e83f0c9a87fa80da66b56a65d2de19f43322324c0fd1ee7cd210f739661a5df51d822645d5454e8411f6
|
data/lib/qsagi.rb
CHANGED
@@ -0,0 +1,66 @@
|
|
1
|
+
module Qsagi
|
2
|
+
class ConfirmedQueue
|
3
|
+
attr_reader :nacked_messages
|
4
|
+
|
5
|
+
def initialize(queue)
|
6
|
+
@queue = queue
|
7
|
+
@nacked_messages = []
|
8
|
+
@unconfirmed_messages = {}
|
9
|
+
@wait_for_confirms = false
|
10
|
+
end
|
11
|
+
|
12
|
+
def connect
|
13
|
+
@queue.connect
|
14
|
+
_confirm_select
|
15
|
+
end
|
16
|
+
|
17
|
+
def disconnect
|
18
|
+
@queue.disconnect
|
19
|
+
end
|
20
|
+
|
21
|
+
def push(message)
|
22
|
+
@unconfirmed_messages[_channel.next_publish_seq_no] = message
|
23
|
+
@queue.push(message)
|
24
|
+
@wait_for_confirms = true
|
25
|
+
end
|
26
|
+
|
27
|
+
def pop(opts={})
|
28
|
+
@queue.pop(opts)
|
29
|
+
end
|
30
|
+
|
31
|
+
def wait_for_confirms
|
32
|
+
_channel.wait_for_confirms if _wait_for_confirms?
|
33
|
+
end
|
34
|
+
|
35
|
+
def _channel
|
36
|
+
@queue.channel
|
37
|
+
end
|
38
|
+
|
39
|
+
def _confirm_messages!(attributes)
|
40
|
+
if attributes[:is_nack]
|
41
|
+
if attributes[:multiple]
|
42
|
+
@nacked_messages += @unconfirmed_messages.select { |k,v| k <= attributes[:delivery_tag] }.values
|
43
|
+
@unconfirmed_messages.delete_if { |k,v| k <= attributes[:delivery_tag] }
|
44
|
+
else
|
45
|
+
@nacked_messages << @unconfirmed_messages.delete(attributes[:delivery_tag])
|
46
|
+
end
|
47
|
+
else
|
48
|
+
if attributes[:multiple]
|
49
|
+
@unconfirmed_messages.delete_if { |k,v| k <= attributes[:delivery_tag] }
|
50
|
+
else
|
51
|
+
@unconfirmed_messages.delete(attributes[:delivery_tag])
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def _confirm_select
|
57
|
+
_channel.confirm_select lambda { |delivery_tag, multiple, is_nack|
|
58
|
+
_confirm_messages!(:delivery_tag => delivery_tag, :multiple => multiple, :is_nack => is_nack)
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
62
|
+
def _wait_for_confirms?
|
63
|
+
@wait_for_confirms
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/lib/qsagi/message.rb
CHANGED
@@ -2,21 +2,17 @@ module Qsagi
|
|
2
2
|
class Message
|
3
3
|
attr_reader :payload
|
4
4
|
|
5
|
-
def initialize(
|
6
|
-
@
|
5
|
+
def initialize(delivery_details, payload)
|
6
|
+
@delivery_details = delivery_details
|
7
7
|
@payload = payload
|
8
8
|
end
|
9
9
|
|
10
10
|
def delivery_tag
|
11
|
-
|
11
|
+
@delivery_details.delivery_tag
|
12
12
|
end
|
13
13
|
|
14
14
|
def exchange
|
15
|
-
|
16
|
-
end
|
17
|
-
|
18
|
-
def _delivery_details
|
19
|
-
@delivery_details ||= @message.fetch(:delivery_details, {})
|
15
|
+
@delivery_details.exchange
|
20
16
|
end
|
21
17
|
end
|
22
18
|
end
|
data/lib/qsagi/queue.rb
CHANGED
@@ -1,58 +1,13 @@
|
|
1
1
|
module Qsagi
|
2
2
|
module Queue
|
3
|
-
def ack(message)
|
4
|
-
@queue.ack(:delivery_tag => message.delivery_tag)
|
5
|
-
end
|
6
|
-
|
7
|
-
def clear
|
8
|
-
loop do
|
9
|
-
message = @queue.pop
|
10
|
-
break if message[:payload] == :queue_empty
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
def connect
|
15
|
-
@client = Bunny.new(:host => self.class.host, :port => self.class.port, :heartbeat => self.class.heartbeat)
|
16
|
-
@client.start
|
17
|
-
@queue = @client.queue(self.class.queue_name, :durable => true, :arguments => {"x-ha-policy" => "all"})
|
18
|
-
@exchange = @client.exchange(self.class._exchange)
|
19
|
-
@queue.bind(@exchange, :key => self.class.queue_name) unless self.class._exchange.empty?
|
20
|
-
end
|
21
|
-
|
22
|
-
def disconnect
|
23
|
-
@client.send(:close_socket) unless @client.nil?
|
24
|
-
end
|
25
|
-
|
26
|
-
def length
|
27
|
-
@queue.status[:message_count]
|
28
|
-
end
|
29
|
-
|
30
|
-
def pop(options = {})
|
31
|
-
auto_ack = options.fetch(:auto_ack, true)
|
32
|
-
message = @queue.pop(:ack => !auto_ack)
|
33
|
-
|
34
|
-
unless message[:payload] == :queue_empty
|
35
|
-
self.class._message_class.new(message, self.class._serializer.deserialize(message[:payload]))
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def push(message)
|
40
|
-
serialized_message = self.class._serializer.serialize(message)
|
41
|
-
@exchange.publish(serialized_message, :key => @queue.name, :persistent => true, :mandatory => true)
|
42
|
-
end
|
43
|
-
|
44
|
-
def reconnect
|
45
|
-
disconnect
|
46
|
-
connect
|
47
|
-
end
|
48
|
-
|
49
3
|
def self.included(klass)
|
50
4
|
klass.extend ClassMethods
|
51
5
|
end
|
52
6
|
|
53
7
|
module ClassMethods
|
54
|
-
def connect(&block)
|
55
|
-
|
8
|
+
def connect(opts={}, &block)
|
9
|
+
options = default_options.merge(opts)
|
10
|
+
queue = _queue(options)
|
56
11
|
|
57
12
|
begin
|
58
13
|
queue.connect
|
@@ -63,8 +18,36 @@ module Qsagi
|
|
63
18
|
end
|
64
19
|
end
|
65
20
|
|
66
|
-
def
|
21
|
+
def _queue(options)
|
22
|
+
standard_queue = StandardQueue.new(options)
|
23
|
+
if options[:queue_type] == :confirmed
|
24
|
+
ConfirmedQueue.new(standard_queue)
|
25
|
+
else
|
26
|
+
standard_queue
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def default_options
|
31
|
+
{
|
32
|
+
:host => host,
|
33
|
+
:port => port,
|
34
|
+
:queue_type => :standard,
|
35
|
+
:heartbeat => heartbeat,
|
36
|
+
:message_class => _message_class,
|
37
|
+
:queue_name => queue_name,
|
38
|
+
:durable => true,
|
39
|
+
:queue_arguments => {"x-ha-policy" => "all"},
|
40
|
+
:persistent => true,
|
41
|
+
:mandatory => true,
|
42
|
+
:serializer => _serializer,
|
43
|
+
:exchange_options => _exchange_options,
|
44
|
+
:exchange => _exchange
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
def exchange(exchange, options = {})
|
67
49
|
@exchange = exchange
|
50
|
+
@exchange_options = {:type => :direct}.merge(options)
|
68
51
|
end
|
69
52
|
|
70
53
|
def message_class(message_class)
|
@@ -79,6 +62,10 @@ module Qsagi
|
|
79
62
|
@exchange || ""
|
80
63
|
end
|
81
64
|
|
65
|
+
def _exchange_options
|
66
|
+
@exchange_options || {}
|
67
|
+
end
|
68
|
+
|
82
69
|
def _message_class
|
83
70
|
@message_class || Qsagi::Message
|
84
71
|
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Qsagi
|
2
|
+
class StandardQueue
|
3
|
+
attr_reader :channel, :options
|
4
|
+
|
5
|
+
def initialize(options={})
|
6
|
+
@options = options
|
7
|
+
end
|
8
|
+
|
9
|
+
def ack(message)
|
10
|
+
@channel.ack(message.delivery_tag, false)
|
11
|
+
end
|
12
|
+
|
13
|
+
def reject(message, options={})
|
14
|
+
@channel.reject(message.delivery_tag, options.fetch(:requeue, true))
|
15
|
+
end
|
16
|
+
|
17
|
+
def clear
|
18
|
+
@queue.purge
|
19
|
+
end
|
20
|
+
|
21
|
+
def connect
|
22
|
+
@client = Bunny.new(
|
23
|
+
:host => options[:host],
|
24
|
+
:port => options[:port],
|
25
|
+
:heartbeat => options[:heartbeat],
|
26
|
+
:continuation_timeout => options[:continuation_timeout]
|
27
|
+
)
|
28
|
+
@client.start
|
29
|
+
@channel = @client.create_channel
|
30
|
+
@exchange = @channel.exchange(options[:exchange], options[:exchange_options])
|
31
|
+
@queue = @channel.queue(options[:queue_name], :durable => options[:durable], :arguments => options[:queue_arguments])
|
32
|
+
@queue.bind(@exchange, :routing_key => options[:queue_name]) unless options[:exchange].empty?
|
33
|
+
end
|
34
|
+
|
35
|
+
def disconnect
|
36
|
+
@client.close unless @client.nil?
|
37
|
+
end
|
38
|
+
|
39
|
+
def length
|
40
|
+
@queue.status[:message_count]
|
41
|
+
end
|
42
|
+
|
43
|
+
def pop(options = {})
|
44
|
+
auto_ack = options.fetch(:auto_ack, true)
|
45
|
+
delivery_info, properties, message = @queue.pop(:ack => !auto_ack)
|
46
|
+
|
47
|
+
unless message.nil?
|
48
|
+
_message_class.new(delivery_info, _serializer.deserialize(message))
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def push(message)
|
53
|
+
serialized_message = options[:serializer].serialize(message)
|
54
|
+
@exchange.publish(serialized_message, :routing_key => @queue.name, :persistent => options[:persistent], :mandatory => options[:mandatory])
|
55
|
+
end
|
56
|
+
|
57
|
+
def reconnect
|
58
|
+
disconnect
|
59
|
+
connect
|
60
|
+
end
|
61
|
+
|
62
|
+
def _message_class
|
63
|
+
options[:message_class]
|
64
|
+
end
|
65
|
+
|
66
|
+
def _serializer
|
67
|
+
options[:serializer]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/lib/qsagi/version.rb
CHANGED
data/qsagi.gemspec
CHANGED
@@ -0,0 +1,33 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Qsagi::ConfirmedQueue do
|
4
|
+
describe "_confirm_messages!" do
|
5
|
+
it "adds a single nacked message to nacked_messages" do
|
6
|
+
queue = Qsagi::ConfirmedQueue.new(nil)
|
7
|
+
queue.instance_variable_set(:@unconfirmed_messages, {2 => "message"})
|
8
|
+
queue._confirm_messages!(:delivery_tag => 2, :multiple => false, :is_nack => true)
|
9
|
+
queue.nacked_messages.should == ["message"]
|
10
|
+
end
|
11
|
+
|
12
|
+
it "adds multiple nacked messages to nacked_messages" do
|
13
|
+
queue = Qsagi::ConfirmedQueue.new(nil)
|
14
|
+
queue.instance_variable_set(:@unconfirmed_messages, {2 => "message", 3 => "other_message"})
|
15
|
+
queue._confirm_messages!(:delivery_tag => 3, :multiple => true, :is_nack => true)
|
16
|
+
queue.nacked_messages.should == ["message", "other_message"]
|
17
|
+
end
|
18
|
+
|
19
|
+
it "removes a single acked message from unconfirmed_messages" do
|
20
|
+
queue = Qsagi::ConfirmedQueue.new(nil)
|
21
|
+
queue.instance_variable_set(:@unconfirmed_messages, {2 => "message", 3 => "other_message"})
|
22
|
+
queue._confirm_messages!(:delivery_tag => 2, :multiple => false, :is_nack => false)
|
23
|
+
queue.instance_variable_get(:@unconfirmed_messages).should == {3 => "other_message"}
|
24
|
+
end
|
25
|
+
|
26
|
+
it "removes multiple acked messages from unconfirmed_messages" do
|
27
|
+
queue = Qsagi::ConfirmedQueue.new(nil)
|
28
|
+
queue.instance_variable_set(:@unconfirmed_messages, {2 => "message", 3 => "other_message", 4 => "this_dude"})
|
29
|
+
queue._confirm_messages!(:delivery_tag => 3, :multiple => true, :is_nack => false)
|
30
|
+
queue.instance_variable_get(:@unconfirmed_messages).should == {4 => "this_dude"}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/spec/qsagi/message_spec.rb
CHANGED
@@ -3,39 +3,21 @@ require "spec_helper"
|
|
3
3
|
describe Qsagi::Message do
|
4
4
|
describe "delivery_tag" do
|
5
5
|
it "returns the delivery_tag" do
|
6
|
-
|
7
|
-
|
8
|
-
:payload => "raw_payload"
|
9
|
-
}
|
10
|
-
Qsagi::Message.new(data, :parsed_payload).delivery_tag.should == "tag"
|
11
|
-
end
|
12
|
-
|
13
|
-
it "gracefully handles no delivery details" do
|
14
|
-
Qsagi::Message.new({}, :parsed_payload).delivery_tag.should be_nil
|
6
|
+
delivery_details = OpenStruct.new(:delivery_tag => "tag")
|
7
|
+
Qsagi::Message.new(delivery_details, :parsed_payload).delivery_tag.should == "tag"
|
15
8
|
end
|
16
9
|
end
|
17
10
|
|
18
11
|
describe "exchange" do
|
19
12
|
it "returns the exchange" do
|
20
|
-
|
21
|
-
|
22
|
-
:payload => "raw_payload"
|
23
|
-
}
|
24
|
-
Qsagi::Message.new(data, :parsed_payload).exchange.should == "the_exchange"
|
25
|
-
end
|
26
|
-
|
27
|
-
it "gracefully handles no delivery details" do
|
28
|
-
Qsagi::Message.new({}, :parsed_payload).exchange.should be_nil
|
13
|
+
delivery_details = OpenStruct.new(:exchange => "the_exchange")
|
14
|
+
Qsagi::Message.new(delivery_details, :parsed_payload).exchange.should == "the_exchange"
|
29
15
|
end
|
30
16
|
end
|
31
17
|
|
32
18
|
describe "payload" do
|
33
19
|
it "returns the parsed payload" do
|
34
|
-
|
35
|
-
:delivery_details => {:delivery_tag => "tag"},
|
36
|
-
:payload => "raw_payload"
|
37
|
-
}
|
38
|
-
Qsagi::Message.new(data, :parsed_payload).payload.should == :parsed_payload
|
20
|
+
Qsagi::Message.new(:deliver_details, :parsed_payload).payload.should == :parsed_payload
|
39
21
|
end
|
40
22
|
end
|
41
23
|
end
|
data/spec/qsagi/queue_spec.rb
CHANGED
@@ -12,7 +12,7 @@ describe Qsagi::Queue do
|
|
12
12
|
describe "self.exchange" do
|
13
13
|
it "configures the exchange" do
|
14
14
|
queue_on_exchange1 = Class.new(ExampleQueue) do
|
15
|
-
exchange "exchange1"
|
15
|
+
exchange "exchange1", :type => :direct
|
16
16
|
end
|
17
17
|
queue_on_exchange2 = Class.new(ExampleQueue) do
|
18
18
|
exchange "exchange2"
|
@@ -54,6 +54,30 @@ describe Qsagi::Queue do
|
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
|
+
describe "reject" do
|
58
|
+
it "rejects the message and places it back on the queue" do
|
59
|
+
ExampleQueue.connect do |queue|
|
60
|
+
queue.push("message")
|
61
|
+
message = queue.pop(:auto_ack => false)
|
62
|
+
queue.reject(message, :requeue => true)
|
63
|
+
end
|
64
|
+
ExampleQueue.connect do |queue|
|
65
|
+
queue.length.should == 1
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
it "rejects and discards the message" do
|
70
|
+
ExampleQueue.connect do |queue|
|
71
|
+
queue.push("message")
|
72
|
+
message = queue.pop(:auto_ack => false)
|
73
|
+
queue.reject(message, :requeue => false)
|
74
|
+
end
|
75
|
+
ExampleQueue.connect do |queue|
|
76
|
+
queue.length.should == 0
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
57
81
|
describe "pop" do
|
58
82
|
it "automatically acks if :auto_ack is not passed in" do
|
59
83
|
ExampleQueue.connect do |queue|
|
@@ -84,4 +108,14 @@ describe Qsagi::Queue do
|
|
84
108
|
end
|
85
109
|
end
|
86
110
|
end
|
111
|
+
|
112
|
+
describe "queue_type confirmed" do
|
113
|
+
it "should use a ConfirmedQueue" do
|
114
|
+
ExampleQueue.connect(:queue_type => :confirmed) do |queue|
|
115
|
+
queue.push("message")
|
116
|
+
queue.wait_for_confirms
|
117
|
+
queue.nacked_messages.size.should == 0
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
87
121
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "qsagi"
|
2
|
+
require "ostruct"
|
2
3
|
|
3
4
|
class ExampleQueue
|
4
5
|
include Qsagi::Queue
|
@@ -22,10 +23,8 @@ end
|
|
22
23
|
|
23
24
|
RSpec.configure do |c|
|
24
25
|
c.before(:each) do
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
queue.delete rescue nil
|
29
|
-
client.send(:close_socket)
|
26
|
+
ExampleQueue.connect do |queue|
|
27
|
+
queue.clear
|
28
|
+
end
|
30
29
|
end
|
31
30
|
end
|
metadata
CHANGED
@@ -1,36 +1,32 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: qsagi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
5
|
-
prerelease:
|
4
|
+
version: 0.1.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Braintree
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2014-05-15 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: bunny
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
17
|
- - ~>
|
20
18
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
19
|
+
version: 1.1.0
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
24
|
- - ~>
|
28
25
|
- !ruby/object:Gem::Version
|
29
|
-
version:
|
26
|
+
version: 1.1.0
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: json
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
31
|
- - ~>
|
36
32
|
- !ruby/object:Gem::Version
|
@@ -38,7 +34,6 @@ dependencies:
|
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
38
|
- - ~>
|
44
39
|
- !ruby/object:Gem::Version
|
@@ -56,41 +51,44 @@ files:
|
|
56
51
|
- README.md
|
57
52
|
- Rakefile
|
58
53
|
- lib/qsagi.rb
|
54
|
+
- lib/qsagi/confirmed_queue.rb
|
59
55
|
- lib/qsagi/default_serializer.rb
|
60
56
|
- lib/qsagi/json_serializer.rb
|
61
57
|
- lib/qsagi/message.rb
|
62
58
|
- lib/qsagi/queue.rb
|
59
|
+
- lib/qsagi/standard_queue.rb
|
63
60
|
- lib/qsagi/version.rb
|
64
61
|
- qsagi.gemspec
|
62
|
+
- spec/qsagi/confirmed_queue_spec.rb
|
65
63
|
- spec/qsagi/json_serializer_spec.rb
|
66
64
|
- spec/qsagi/message_spec.rb
|
67
65
|
- spec/qsagi/queue_spec.rb
|
68
66
|
- spec/spec_helper.rb
|
69
67
|
homepage: https://github.com/braintree/qsagi
|
70
68
|
licenses: []
|
69
|
+
metadata: {}
|
71
70
|
post_install_message:
|
72
71
|
rdoc_options: []
|
73
72
|
require_paths:
|
74
73
|
- lib
|
75
74
|
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
-
none: false
|
77
75
|
requirements:
|
78
|
-
- -
|
76
|
+
- - '>='
|
79
77
|
- !ruby/object:Gem::Version
|
80
78
|
version: '0'
|
81
79
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
-
none: false
|
83
80
|
requirements:
|
84
|
-
- -
|
81
|
+
- - '>='
|
85
82
|
- !ruby/object:Gem::Version
|
86
83
|
version: '0'
|
87
84
|
requirements: []
|
88
85
|
rubyforge_project:
|
89
|
-
rubygems_version:
|
86
|
+
rubygems_version: 2.2.2
|
90
87
|
signing_key:
|
91
|
-
specification_version:
|
88
|
+
specification_version: 4
|
92
89
|
summary: A friendly way to talk to RabbitMQ
|
93
90
|
test_files:
|
91
|
+
- spec/qsagi/confirmed_queue_spec.rb
|
94
92
|
- spec/qsagi/json_serializer_spec.rb
|
95
93
|
- spec/qsagi/message_spec.rb
|
96
94
|
- spec/qsagi/queue_spec.rb
|