hot_bunnies 1.1.3-java → 1.2.0-java
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/.gitignore +1 -0
- data/.rvmrc +1 -1
- data/.travis.yml +8 -0
- data/Gemfile +5 -1
- data/LICENSE +20 -0
- data/README.md +42 -0
- data/hot_bunnies.gemspec +1 -1
- data/lib/ext/rabbitmq-client.jar +0 -0
- data/lib/hot_bunnies/channel.rb +11 -5
- data/lib/hot_bunnies/exchange.rb +35 -9
- data/lib/hot_bunnies/queue.rb +28 -28
- data/lib/hot_bunnies/version.rb +1 -1
- data/lib/hot_bunnies.rb +4 -2
- data/spec/integration/alternate_exchanges_spec.rb +36 -0
- data/spec/integration/exchange_bind_spec.rb +35 -0
- data/spec/integration/exchange_declare_spec.rb +113 -0
- data/spec/integration/publisher_confirmations_spec.rb +51 -0
- data/spec/integration/queue_bind_spec.rb +56 -0
- data/spec/integration/queue_declare_spec.rb +44 -0
- data/spec/integration/queue_delete_spec.rb +23 -0
- data/spec/integration/queue_purge_spec.rb +38 -0
- data/spec/integration/queue_unbind_spec.rb +53 -0
- data/spec/integration/sender_selected_distribution_spec.rb +45 -0
- data/spec/spec_helper.rb +16 -0
- metadata +42 -27
data/.gitignore
CHANGED
data/.rvmrc
CHANGED
@@ -1 +1 @@
|
|
1
|
-
rvm --create use jruby
|
1
|
+
rvm --create use jruby@hot_bunnies
|
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Theo Hultberg
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# What is Hot Bunnies
|
2
|
+
|
3
|
+
Hot Bunnies is an idiomatic, fast and well-maintained (J)Ruby DSL on top of the [RabbitMQ Java client](http://www.rabbitmq.com/api-guide.html). It strives to combine
|
4
|
+
strong parts of the Java client with over 3 years of [Ruby amqp gem](https://github.com/ruby-amqp/amqp) development experience.
|
5
|
+
|
6
|
+
## Why Hot Bunnies
|
7
|
+
|
8
|
+
* Concurrency support on the JVM is excellent, with many tools & approaches available. Lets make use of it.
|
9
|
+
* RabbitMQ Java client is rock solid and supports every RabbitMQ feature. Very nice.
|
10
|
+
* It is screaming fast thanks to all the heavy duty being done in the pretty efficient & lightweight Java code.
|
11
|
+
* It uses synchronous APIs where it makes sense and asynchronous APIs where it makes sense. Some other [Ruby RabbitMQ clients](https://github.com/ruby-amqp)
|
12
|
+
only use one or the other.
|
13
|
+
* [amqp gem](https://github.com/ruby-amqp/amqp) has certain amount of baggage it cannot drop because of backwards compatibility concerns. Hot Bunnies is a
|
14
|
+
clean room design, much more open to radical new ideas.
|
15
|
+
* Someone just *had* to come up with a library called Hot Bunnies. Are your bunnies hot?
|
16
|
+
|
17
|
+
|
18
|
+
## What Hot Bunnies is not
|
19
|
+
|
20
|
+
Hot Bunnies is not
|
21
|
+
|
22
|
+
* A replacement for the RabbitMQ Java client
|
23
|
+
* An attempt to re-create 100% of the amqp gem API on top of the Java client
|
24
|
+
* A "work queue" like Resque
|
25
|
+
* A cure for cancer
|
26
|
+
|
27
|
+
|
28
|
+
## Continuous Integration
|
29
|
+
|
30
|
+
[](http://travis-ci.org/ruby-amqp/hot_bunnies)
|
31
|
+
|
32
|
+
CI is hosted by [travis-ci.org](http://travis-ci.org)
|
33
|
+
|
34
|
+
|
35
|
+
## License
|
36
|
+
|
37
|
+
MIT, see LICENSE in the repository root
|
38
|
+
|
39
|
+
|
40
|
+
## Copyright
|
41
|
+
|
42
|
+
Theo Hultberg, 2011.
|
data/hot_bunnies.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.name = 'hot_bunnies'
|
10
10
|
s.version = HotBunnies::VERSION
|
11
11
|
s.platform = 'java'
|
12
|
-
s.authors = ['Theo Hultberg']
|
12
|
+
s.authors = ['Theo Hultberg', 'Michael S. Klishin']
|
13
13
|
s.email = ['theo@burtcorp.com']
|
14
14
|
s.homepage = 'http://github.com/iconara/hot_bunnies'
|
15
15
|
s.summary = %q{Ruby wrapper for the RabbitMQ Java driver}
|
data/lib/ext/rabbitmq-client.jar
CHANGED
Binary file
|
data/lib/hot_bunnies/channel.rb
CHANGED
@@ -5,22 +5,28 @@ module HotBunnies
|
|
5
5
|
def queue(name, options={})
|
6
6
|
Queue.new(self, name, options)
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
def exchange(name, options={})
|
10
|
-
Exchange.new(self, name, options)
|
10
|
+
exchange = Exchange.new(self, name, options)
|
11
|
+
exchange.declare!
|
12
|
+
exchange
|
13
|
+
end
|
14
|
+
|
15
|
+
def default_exchange
|
16
|
+
self.exchange("", :durable => true, :auto_delete => false)
|
11
17
|
end
|
12
|
-
|
18
|
+
|
13
19
|
def qos(options={})
|
14
20
|
if options.size == 1 && options[:prefetch_count]
|
15
21
|
then basic_qos(options[:prefetch_count])
|
16
22
|
else basic_qos(options.fetch(:prefetch_size, 0), options.fetch(:prefetch_count, 0), options.fetch(:global, false))
|
17
23
|
end
|
18
24
|
end
|
19
|
-
|
25
|
+
|
20
26
|
def prefetch=(n)
|
21
27
|
qos(:prefetch_count => n)
|
22
28
|
end
|
23
|
-
|
29
|
+
|
24
30
|
def on_return(&block)
|
25
31
|
self.set_return_listener(block)
|
26
32
|
end
|
data/lib/hot_bunnies/exchange.rb
CHANGED
@@ -3,32 +3,58 @@
|
|
3
3
|
module HotBunnies
|
4
4
|
class Exchange
|
5
5
|
attr_reader :name, :channel
|
6
|
-
|
6
|
+
|
7
7
|
def initialize(channel, name, options={})
|
8
8
|
@channel = channel
|
9
9
|
@name = name
|
10
10
|
@options = {:type => :fanout, :durable => false, :auto_delete => false, :internal => false, :passive => false}.merge(options)
|
11
|
-
declare!
|
12
11
|
end
|
13
|
-
|
12
|
+
|
14
13
|
def publish(body, options={})
|
15
14
|
options = {:routing_key => '', :mandatory => false, :immediate => false}.merge(options)
|
16
|
-
@channel.basic_publish(@name, options[:routing_key], options[:mandatory], options[:immediate],
|
15
|
+
@channel.basic_publish(@name, options[:routing_key], options[:mandatory], options[:immediate], build_properties_from(options.fetch(:properties, Hash.new)), body.to_java_bytes)
|
17
16
|
end
|
18
|
-
|
17
|
+
|
19
18
|
def delete(options={})
|
20
19
|
@channel.exchange_delete(@name, options.fetch(:if_unused, false))
|
21
20
|
end
|
22
|
-
|
23
|
-
|
24
|
-
|
21
|
+
|
22
|
+
def bind(exchange, options={})
|
23
|
+
exchange_name = if exchange.respond_to?(:name) then exchange.name else exchange.to_s end
|
24
|
+
@channel.exchange_bind(@name, exchange_name, options.fetch(:routing_key, ''))
|
25
|
+
end
|
26
|
+
|
25
27
|
def declare!
|
26
28
|
unless @name == ''
|
27
29
|
if @options[:passive]
|
28
30
|
then @channel.exchange_declare_passive(@name)
|
29
|
-
else @channel.exchange_declare(@name, @options[:type].to_s, @options[:durable], @options[:auto_delete], @options[:internal],
|
31
|
+
else @channel.exchange_declare(@name, @options[:type].to_s, @options[:durable], @options[:auto_delete], @options[:internal], @options[:arguments])
|
30
32
|
end
|
31
33
|
end
|
32
34
|
end
|
35
|
+
|
36
|
+
|
37
|
+
protected
|
38
|
+
|
39
|
+
def build_properties_from(props = {})
|
40
|
+
builder = AMQP::BasicProperties::Builder.new
|
41
|
+
|
42
|
+
builder.content_type(props[:content_type]).
|
43
|
+
content_encoding(props[:content_encoding]).
|
44
|
+
headers(props[:headers]).
|
45
|
+
delivery_mode(props[:persistent] ? 2 : 1).
|
46
|
+
priority(props[:priority]).
|
47
|
+
correlation_id(props[:correlation_id]).
|
48
|
+
reply_to(props[:reply_to]).
|
49
|
+
expiration(props[:expiration]).
|
50
|
+
message_id(props[:message_id]).
|
51
|
+
timestamp(props[:timestamp]).
|
52
|
+
type(props[:type]).
|
53
|
+
user_id(props[:user_id]).
|
54
|
+
app_id(props[:app_id]).
|
55
|
+
cluster_id(props[:cluster_id]).
|
56
|
+
build
|
57
|
+
end # build_properties_from(props)
|
58
|
+
|
33
59
|
end
|
34
60
|
end
|
data/lib/hot_bunnies/queue.rb
CHANGED
@@ -3,32 +3,32 @@
|
|
3
3
|
module HotBunnies
|
4
4
|
class Queue
|
5
5
|
attr_reader :name, :channel
|
6
|
-
|
6
|
+
|
7
7
|
def initialize(channel, name, options={})
|
8
8
|
@channel = channel
|
9
9
|
@name = name
|
10
|
-
@options = {:durable => false, :exclusive => false, :auto_delete => false, :passive => false}.merge(options)
|
10
|
+
@options = {:durable => false, :exclusive => false, :auto_delete => false, :passive => false, :arguments => Hash.new}.merge(options)
|
11
11
|
declare!
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
def bind(exchange, options={})
|
15
15
|
exchange_name = if exchange.respond_to?(:name) then exchange.name else exchange.to_s end
|
16
|
-
@channel.queue_bind(@name, exchange_name, options.fetch(:routing_key, ''))
|
16
|
+
@channel.queue_bind(@name, exchange_name, options.fetch(:routing_key, ''), options[:arguments])
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
def unbind(exchange, options={})
|
20
20
|
exchange_name = if exchange.respond_to?(:name) then exchange.name else exchange.to_s end
|
21
21
|
@channel.queue_unbind(@name, exchange_name, options.fetch(:routing_key, ''))
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
def delete
|
25
25
|
@channel.queue_delete(@name)
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
def purge
|
29
29
|
@channel.queue_purge(@name)
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
32
|
def get(options={})
|
33
33
|
response = @channel.basic_get(@name, !options.fetch(:ack, false))
|
34
34
|
if response
|
@@ -36,35 +36,35 @@ module HotBunnies
|
|
36
36
|
else nil
|
37
37
|
end
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
40
|
def subscribe(options={}, &block)
|
41
41
|
subscription = Subscription.new(@channel, @name, options)
|
42
42
|
subscription.each(options, &block) if block
|
43
43
|
subscription
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
46
|
def status
|
47
47
|
response = @channel.queue_declare_passive(@name)
|
48
48
|
[response.message_count, response.consumer_count]
|
49
49
|
end
|
50
50
|
|
51
51
|
private
|
52
|
-
|
52
|
+
|
53
53
|
def declare!
|
54
54
|
response = if @options[:passive]
|
55
55
|
then @channel.queue_declare_passive(@name)
|
56
|
-
else @channel.queue_declare(@name, @options[:durable], @options[:exclusive], @options[:auto_delete],
|
56
|
+
else @channel.queue_declare(@name, @options[:durable], @options[:exclusive], @options[:auto_delete], @options[:arguments])
|
57
57
|
end
|
58
58
|
@name = response.queue
|
59
59
|
end
|
60
|
-
|
60
|
+
|
61
61
|
class Subscription
|
62
62
|
def initialize(channel, queue_name, options={})
|
63
63
|
@channel = channel
|
64
64
|
@queue_name = queue_name
|
65
65
|
@ack = options.fetch(:ack, false)
|
66
66
|
end
|
67
|
-
|
67
|
+
|
68
68
|
def each(options={}, &block)
|
69
69
|
raise 'The subscription already has a message listener' if @subscriber
|
70
70
|
if options.fetch(:blocking, true)
|
@@ -86,16 +86,16 @@ module HotBunnies
|
|
86
86
|
@channel.basic_cancel(@subscriber.consumer_tag)
|
87
87
|
@executor.shutdown_now if @executor && @shut_down_executor
|
88
88
|
end
|
89
|
-
|
89
|
+
|
90
90
|
private
|
91
|
-
|
91
|
+
|
92
92
|
def run(&block)
|
93
93
|
@subscriber = BlockingSubscriber.new(@channel, self)
|
94
94
|
@channel.basic_consume(@queue_name, !@ack, @subscriber.consumer)
|
95
95
|
@subscriber.on_message(&block)
|
96
96
|
end
|
97
97
|
end
|
98
|
-
|
98
|
+
|
99
99
|
class Headers
|
100
100
|
def initialize(channel, consumer_tag, envelope, properties)
|
101
101
|
@channel = channel
|
@@ -103,31 +103,31 @@ module HotBunnies
|
|
103
103
|
@envelope = envelope
|
104
104
|
@properties = properties
|
105
105
|
end
|
106
|
-
|
106
|
+
|
107
107
|
def ack(options={})
|
108
108
|
@channel.basic_ack(delivery_tag, options.fetch(:multiple, false))
|
109
109
|
end
|
110
|
-
|
110
|
+
|
111
111
|
def reject(options={})
|
112
112
|
@channel.basic_ack(delivery_tag, options.fetch(:requeue, false))
|
113
113
|
end
|
114
|
-
|
114
|
+
|
115
115
|
def delivery_tag
|
116
116
|
@envelope.delivery_tag
|
117
117
|
end
|
118
118
|
end
|
119
|
-
|
119
|
+
|
120
120
|
module Subscriber
|
121
121
|
def start
|
122
122
|
# to be implemented by the host class
|
123
123
|
end
|
124
|
-
|
124
|
+
|
125
125
|
def on_message(&block)
|
126
126
|
raise ArgumentError, 'Message listener already registered for this subscriber' if @subscriber
|
127
127
|
@subscriber = block
|
128
128
|
start
|
129
129
|
end
|
130
|
-
|
130
|
+
|
131
131
|
def handle_message(consumer_tag, envelope, properties, body_bytes)
|
132
132
|
body = String.from_java_bytes(body_bytes)
|
133
133
|
case @subscriber.arity
|
@@ -137,22 +137,22 @@ module HotBunnies
|
|
137
137
|
end
|
138
138
|
end
|
139
139
|
end
|
140
|
-
|
140
|
+
|
141
141
|
class BlockingSubscriber
|
142
142
|
include Subscriber
|
143
|
-
|
143
|
+
|
144
144
|
attr_reader :consumer
|
145
|
-
|
145
|
+
|
146
146
|
def initialize(channel, subscription)
|
147
147
|
@channel = channel
|
148
148
|
@subscription = subscription
|
149
149
|
@consumer = QueueingConsumer.new(@channel)
|
150
150
|
end
|
151
|
-
|
151
|
+
|
152
152
|
def consumer_tag
|
153
153
|
@consumer.consumer_tag
|
154
154
|
end
|
155
|
-
|
155
|
+
|
156
156
|
def start
|
157
157
|
super
|
158
158
|
while delivery = @consumer.next_delivery
|
data/lib/hot_bunnies/version.rb
CHANGED
data/lib/hot_bunnies.rb
CHANGED
@@ -12,13 +12,15 @@ module HotBunnies
|
|
12
12
|
import com.rabbitmq.client.DefaultConsumer
|
13
13
|
import com.rabbitmq.client.QueueingConsumer
|
14
14
|
|
15
|
+
import com.rabbitmq.client.AMQP
|
16
|
+
|
15
17
|
CONNECTION_PROPERTIES = [:host, :port, :virtual_host, :connection_timeout, :username, :password]
|
16
|
-
|
18
|
+
|
17
19
|
def self.connect(options={})
|
18
20
|
cf = ConnectionFactory.new
|
19
21
|
CONNECTION_PROPERTIES.each do |property|
|
20
22
|
if options[property]
|
21
|
-
cf.send("#{property}=".to_sym, options[property])
|
23
|
+
cf.send("#{property}=".to_sym, options[property])
|
22
24
|
end
|
23
25
|
end
|
24
26
|
cf.new_connection
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "Any exchange" do
|
4
|
+
|
5
|
+
#
|
6
|
+
# Environment
|
7
|
+
#
|
8
|
+
|
9
|
+
let(:connection) { HotBunnies.connect }
|
10
|
+
let(:channel) { connection.create_channel }
|
11
|
+
|
12
|
+
after :each do
|
13
|
+
channel.close
|
14
|
+
connection.close
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
#
|
19
|
+
# Examples
|
20
|
+
#
|
21
|
+
|
22
|
+
it "can have an alternate exchange (a RabbitMQ-specific extension to AMQP 0.9.1)" do
|
23
|
+
queue = channel.queue("", :auto_delete => true)
|
24
|
+
|
25
|
+
fe = channel.exchange("hot_bunnies.extensions.alternate_xchanges.fanout1")
|
26
|
+
de = channel.exchange("hot_bunnies.extensions.alternate_xchanges.direct1", :arguments => {
|
27
|
+
"alternate-exchange" => fe.name
|
28
|
+
})
|
29
|
+
|
30
|
+
queue.bind(fe)
|
31
|
+
de.publish("1010", :routing_key => "", :mandatory => true)
|
32
|
+
|
33
|
+
mc, _ = queue.status
|
34
|
+
mc.should == 1
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe HotBunnies::Exchange do
|
4
|
+
let(:connection) { HotBunnies.connect }
|
5
|
+
let(:channel) { connection.create_channel }
|
6
|
+
|
7
|
+
after :each do
|
8
|
+
channel.close
|
9
|
+
connection.close
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should bind two exchanges using exchange instances" do
|
13
|
+
source = channel.exchange("hot_bunnies.spec.exchanges.source", :auto_delete => true)
|
14
|
+
destianation = channel.exchange("hot_bunnies.spec.exchanges.destination", :auto_delete => true)
|
15
|
+
|
16
|
+
queue = channel.queue("", :auto_delete => true)
|
17
|
+
queue.bind(destianation)
|
18
|
+
|
19
|
+
destianation.bind(source)
|
20
|
+
source.publish("")
|
21
|
+
queue.get.should_not be_nil
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should bind two exchanges using exchange name" do
|
25
|
+
source = channel.exchange("hot_bunnies.spec.exchanges.source", :auto_delete => true)
|
26
|
+
destianation = channel.exchange("hot_bunnies.spec.exchanges.destination", :auto_delete => true)
|
27
|
+
|
28
|
+
queue = channel.queue("", :auto_delete => true)
|
29
|
+
queue.bind(destianation)
|
30
|
+
|
31
|
+
destianation.bind(source.name)
|
32
|
+
source.publish("")
|
33
|
+
queue.get.should_not be_nil
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "Direct exchange" do
|
4
|
+
let(:connection) { HotBunnies.connect }
|
5
|
+
let(:channel) { connection.create_channel }
|
6
|
+
|
7
|
+
after :each do
|
8
|
+
channel.close
|
9
|
+
connection.close
|
10
|
+
end
|
11
|
+
|
12
|
+
it "can be declared" do
|
13
|
+
exchange = channel.exchange("hot_bunnies.exchanges.direct1", :type => :direct)
|
14
|
+
queue = channel.queue("", :auto_delete => true)
|
15
|
+
|
16
|
+
queue.bind(exchange, :routing_key => "abc")
|
17
|
+
|
18
|
+
exchange.publish("", :routing_key => "xyz")
|
19
|
+
exchange.publish("", :routing_key => "abc")
|
20
|
+
|
21
|
+
sleep(0.3)
|
22
|
+
|
23
|
+
mc, cc = queue.status
|
24
|
+
mc.should == 1
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
describe "Fanout exchange" do
|
31
|
+
let(:connection) { HotBunnies.connect }
|
32
|
+
let(:channel) { connection.create_channel }
|
33
|
+
|
34
|
+
after :each do
|
35
|
+
channel.close
|
36
|
+
connection.close
|
37
|
+
end
|
38
|
+
|
39
|
+
it "can be declared" do
|
40
|
+
exchange = channel.exchange("hot_bunnies.exchanges.fanout1", :type => :fanout)
|
41
|
+
queue = channel.queue("", :auto_delete => true)
|
42
|
+
|
43
|
+
queue.bind(exchange)
|
44
|
+
|
45
|
+
exchange.publish("")
|
46
|
+
exchange.publish("", :routing_key => "xyz")
|
47
|
+
exchange.publish("", :routing_key => "abc")
|
48
|
+
|
49
|
+
sleep(0.5)
|
50
|
+
|
51
|
+
mc, cc = queue.status
|
52
|
+
mc.should == 3
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
|
58
|
+
describe "Topic exchange" do
|
59
|
+
let(:connection) { HotBunnies.connect }
|
60
|
+
let(:channel) { connection.create_channel }
|
61
|
+
|
62
|
+
after :each do
|
63
|
+
channel.close
|
64
|
+
connection.close
|
65
|
+
end
|
66
|
+
|
67
|
+
it "can be declared" do
|
68
|
+
exchange = channel.exchange("hot_bunnies.exchanges.topic1", :type => :topic)
|
69
|
+
queue = channel.queue("", :auto_delete => true)
|
70
|
+
|
71
|
+
queue.bind(exchange, :routing_key => "log.*")
|
72
|
+
|
73
|
+
exchange.publish("")
|
74
|
+
exchange.publish("", :routing_key => "accounts.signup")
|
75
|
+
exchange.publish("", :routing_key => "log.info")
|
76
|
+
exchange.publish("", :routing_key => "log.warn")
|
77
|
+
|
78
|
+
sleep(0.5)
|
79
|
+
|
80
|
+
mc, cc = queue.status
|
81
|
+
mc.should == 2
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
|
87
|
+
describe "Headers exchange" do
|
88
|
+
let(:connection) { HotBunnies.connect }
|
89
|
+
let(:channel) { connection.create_channel }
|
90
|
+
|
91
|
+
after :each do
|
92
|
+
channel.close
|
93
|
+
connection.close
|
94
|
+
end
|
95
|
+
|
96
|
+
it "can be declared" do
|
97
|
+
exchange = channel.exchange("hot_bunnies.exchanges.headers1", :type => :headers)
|
98
|
+
queue = channel.queue("", :auto_delete => true)
|
99
|
+
|
100
|
+
queue.bind(exchange, :arguments => { 'x-match' => 'all', 'arch' => "x86_64", 'os' => "linux" })
|
101
|
+
|
102
|
+
exchange.publish "For linux/IA64", :properties => { :headers => { 'arch' => "x86_64", 'os' => 'linux' } }
|
103
|
+
exchange.publish "For linux/x86", :properties => { :headers => { 'arch' => "x86", 'os' => 'linux' } }
|
104
|
+
exchange.publish "For any linux", :properties => { :headers => { 'os' => 'linux' } }
|
105
|
+
exchange.publish "For OS X", :properties => { :headers => { 'os' => 'macosx' } }
|
106
|
+
exchange.publish "For solaris/IA64", :properties => { :headers => { 'os' => 'solaris', 'arch' => 'x86_64' } }
|
107
|
+
|
108
|
+
sleep(0.3)
|
109
|
+
|
110
|
+
mc, cc = queue.status
|
111
|
+
mc.should == 1
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "Any channel" do
|
4
|
+
|
5
|
+
#
|
6
|
+
# Environment
|
7
|
+
#
|
8
|
+
|
9
|
+
let(:connection) { HotBunnies.connect }
|
10
|
+
let(:channel) { connection.create_channel }
|
11
|
+
|
12
|
+
after :each do
|
13
|
+
channel.close
|
14
|
+
connection.close
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:latch) { java.util.concurrent.CountDownLatch.new(1) }
|
18
|
+
|
19
|
+
class ConfirmationListener
|
20
|
+
include com.rabbitmq.client.ConfirmListener
|
21
|
+
|
22
|
+
def initialize(latch)
|
23
|
+
@latch = latch
|
24
|
+
end
|
25
|
+
|
26
|
+
def handle_ack(delivery_tag, multiple)
|
27
|
+
@latch.count_down
|
28
|
+
end
|
29
|
+
|
30
|
+
def handle_nack(delivery_tag, multiple)
|
31
|
+
@latch.count_down
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
#
|
37
|
+
# Examples
|
38
|
+
#
|
39
|
+
|
40
|
+
it "can use publisher confirmations with listener objects" do
|
41
|
+
channel.confirm_select
|
42
|
+
channel.confirm_listener = ConfirmationListener.new(latch)
|
43
|
+
|
44
|
+
queue = channel.queue("", :auto_delete => true)
|
45
|
+
Thread.new do
|
46
|
+
channel.default_exchange.publish("", :routing_key => queue.name)
|
47
|
+
end
|
48
|
+
|
49
|
+
latch.await
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
|
4
|
+
describe "Any queue" do
|
5
|
+
|
6
|
+
#
|
7
|
+
# Environment
|
8
|
+
#
|
9
|
+
|
10
|
+
let(:connection) { HotBunnies.connect }
|
11
|
+
let(:channel) { connection.create_channel }
|
12
|
+
|
13
|
+
after :each do
|
14
|
+
channel.close
|
15
|
+
connection.close
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
#
|
20
|
+
# Examples
|
21
|
+
#
|
22
|
+
|
23
|
+
it "can be bound to amq.fanout" do
|
24
|
+
exchange = channel.exchange("amq.fanout", :type => :fanout, :durable => true, :auto_delete => false)
|
25
|
+
queue = channel.queue("", :auto_delete => true)
|
26
|
+
exchange.publish("")
|
27
|
+
queue.get.should be_nil
|
28
|
+
|
29
|
+
queue.bind(exchange)
|
30
|
+
|
31
|
+
exchange.publish("", :routing_key => queue.name)
|
32
|
+
queue.get.should_not be_nil
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
it "can be bound to a newly declared exchange" do
|
37
|
+
exchange = channel.exchange("hot.bunnies.fanout", :type => :fanout, :durable => false, :auto_delete => true)
|
38
|
+
queue = channel.queue("", :auto_delete => true)
|
39
|
+
exchange.publish("")
|
40
|
+
queue.get.should be_nil
|
41
|
+
|
42
|
+
queue.bind(exchange)
|
43
|
+
|
44
|
+
exchange.publish("", :routing_key => queue.name)
|
45
|
+
queue.get.should_not be_nil
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
it "is automatically bound to the default exchange" do
|
50
|
+
exchange = channel.default_exchange
|
51
|
+
queue = channel.queue("", :auto_delete => true)
|
52
|
+
|
53
|
+
exchange.publish("", :routing_key => queue.name)
|
54
|
+
queue.get.should_not be_nil
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
|
4
|
+
describe "Queue" do
|
5
|
+
context "with a server-generated name" do
|
6
|
+
let(:connection) { HotBunnies.connect }
|
7
|
+
let(:channel) { connection.create_channel }
|
8
|
+
|
9
|
+
after :each do
|
10
|
+
channel.close
|
11
|
+
connection.close
|
12
|
+
end
|
13
|
+
|
14
|
+
it "can be declared as auto-deleted" do
|
15
|
+
channel.queue("", :auto_delete => true)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "can be declared as auto-deleted and non-durable" do
|
19
|
+
channel.queue("", :auto_delete => true, :durable => false)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "can be declared as NON-auto-deleted" do
|
23
|
+
channel.queue("", :auto_delete => false)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "can be declared as NON-durable" do
|
27
|
+
channel.queue("", :durable => false)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "can be declared with additional attributes like x-message-ttle" do
|
31
|
+
queue = channel.queue("", :durable => false, :arguments => { 'x-message-ttl' => 2000 })
|
32
|
+
exchange = channel.exchange("", :type => :direct)
|
33
|
+
|
34
|
+
100.times do |i|
|
35
|
+
exchange.publish("Message #{i}", :routing_key => queue.name)
|
36
|
+
end
|
37
|
+
|
38
|
+
queue.get.should_not be_nil
|
39
|
+
sleep(2.1)
|
40
|
+
|
41
|
+
queue.get.should be_nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
|
4
|
+
describe "Client-defined queue" do
|
5
|
+
|
6
|
+
#
|
7
|
+
# Environment
|
8
|
+
#
|
9
|
+
|
10
|
+
let(:connection) { HotBunnies.connect }
|
11
|
+
let(:channel) { connection.create_channel }
|
12
|
+
|
13
|
+
after :each do
|
14
|
+
channel.close
|
15
|
+
connection.close
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
it "can be deleted" do
|
20
|
+
queue = channel.queue("", :auto_delete => true)
|
21
|
+
queue.delete
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
|
4
|
+
describe "Any queue" do
|
5
|
+
|
6
|
+
#
|
7
|
+
# Environment
|
8
|
+
#
|
9
|
+
|
10
|
+
let(:connection) { HotBunnies.connect }
|
11
|
+
let(:channel) { connection.create_channel }
|
12
|
+
|
13
|
+
after :each do
|
14
|
+
channel.close
|
15
|
+
connection.close
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
#
|
20
|
+
# Examples
|
21
|
+
#
|
22
|
+
|
23
|
+
it "can be purged" do
|
24
|
+
exchange = channel.exchange("amq.fanout", :type => :fanout, :durable => true, :auto_delete => false)
|
25
|
+
queue = channel.queue("", :auto_delete => true)
|
26
|
+
exchange.publish("")
|
27
|
+
queue.get.should be_nil
|
28
|
+
queue.purge
|
29
|
+
queue.get.should be_nil
|
30
|
+
|
31
|
+
queue.bind(exchange)
|
32
|
+
|
33
|
+
exchange.publish("", :routing_key => queue.name)
|
34
|
+
queue.get.should_not be_nil
|
35
|
+
queue.purge
|
36
|
+
queue.get.should be_nil
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
|
4
|
+
describe "Any queue" do
|
5
|
+
|
6
|
+
#
|
7
|
+
# Environment
|
8
|
+
#
|
9
|
+
|
10
|
+
let(:connection) { HotBunnies.connect }
|
11
|
+
let(:channel) { connection.create_channel }
|
12
|
+
|
13
|
+
after :each do
|
14
|
+
channel.close
|
15
|
+
connection.close
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
#
|
20
|
+
# Examples
|
21
|
+
#
|
22
|
+
|
23
|
+
it "can be unbound from amq.fanout" do
|
24
|
+
exchange = channel.exchange("amq.fanout", :type => :fanout, :durable => true, :auto_delete => false)
|
25
|
+
queue = channel.queue("", :auto_delete => true)
|
26
|
+
|
27
|
+
queue.bind(exchange)
|
28
|
+
|
29
|
+
exchange.publish("", :routing_key => queue.name)
|
30
|
+
queue.get.should_not be_nil
|
31
|
+
|
32
|
+
queue.unbind(exchange)
|
33
|
+
|
34
|
+
exchange.publish("")
|
35
|
+
queue.get.should be_nil
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
it "can be unbound from a client-declared exchange" do
|
40
|
+
exchange = channel.exchange("hot.bunnies.fanout#{Time.now.to_i}", :type => :fanout, :durable => false)
|
41
|
+
queue = channel.queue("", :auto_delete => true)
|
42
|
+
|
43
|
+
queue.bind(exchange)
|
44
|
+
|
45
|
+
exchange.publish("", :routing_key => queue.name)
|
46
|
+
queue.get.should_not be_nil
|
47
|
+
|
48
|
+
queue.unbind(exchange)
|
49
|
+
|
50
|
+
exchange.publish("")
|
51
|
+
queue.get.should be_nil
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "Any AMQP 0.9.1 client using RabbitMQ" do
|
4
|
+
|
5
|
+
#
|
6
|
+
# Environment
|
7
|
+
#
|
8
|
+
|
9
|
+
let(:connection) { HotBunnies.connect }
|
10
|
+
let(:channel) { connection.create_channel }
|
11
|
+
|
12
|
+
after :each do
|
13
|
+
channel.close
|
14
|
+
connection.close
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
#
|
19
|
+
# Examples
|
20
|
+
#
|
21
|
+
|
22
|
+
it "can have use CC and BCC headers for sender selected routing (a RabbitMQ-specific extension to AMQP 0.9.1)" do
|
23
|
+
queue1 = channel.queue("", :auto_delete => true)
|
24
|
+
queue2 = channel.queue("", :auto_delete => true)
|
25
|
+
queue3 = channel.queue("", :auto_delete => true)
|
26
|
+
queue4 = channel.queue("", :auto_delete => true)
|
27
|
+
|
28
|
+
channel.default_exchange.publish("1010", :properties => {
|
29
|
+
:headers => {
|
30
|
+
"CC" => [queue2.name],
|
31
|
+
"BCC" => [queue3.name]
|
32
|
+
}
|
33
|
+
}, :routing_key => queue1.name)
|
34
|
+
|
35
|
+
mc1, _ = queue1.status
|
36
|
+
mc2, _ = queue2.status
|
37
|
+
mc3, _ = queue3.status
|
38
|
+
mc4, _ = queue4.status
|
39
|
+
|
40
|
+
mc1.should == 1
|
41
|
+
mc2.should == 1
|
42
|
+
mc3.should == 1
|
43
|
+
mc4.should == 0
|
44
|
+
end
|
45
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
|
4
|
+
|
5
|
+
require 'bundler'
|
6
|
+
Bundler.setup(:default, :test)
|
7
|
+
|
8
|
+
case RUBY_VERSION
|
9
|
+
when "1.8.7" then
|
10
|
+
class Array
|
11
|
+
alias sample choice
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
require "hot_bunnies"
|
metadata
CHANGED
@@ -2,21 +2,22 @@
|
|
2
2
|
name: hot_bunnies
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 1.
|
5
|
+
version: 1.2.0
|
6
6
|
platform: java
|
7
7
|
authors:
|
8
|
-
- Theo Hultberg
|
8
|
+
- Theo Hultberg
|
9
|
+
- Michael S. Klishin
|
9
10
|
autorequire:
|
10
11
|
bindir: bin
|
11
12
|
cert_chain: []
|
12
13
|
|
13
|
-
date: 2011-
|
14
|
+
date: 2011-10-04 00:00:00 +04:00
|
14
15
|
default_executable:
|
15
16
|
dependencies: []
|
16
17
|
|
17
18
|
description: A object oriented interface to RabbitMQ that uses the Java driver under the hood
|
18
19
|
email:
|
19
|
-
- theo@burtcorp.com
|
20
|
+
- theo@burtcorp.com
|
20
21
|
executables: []
|
21
22
|
|
22
23
|
extensions: []
|
@@ -24,21 +25,35 @@ extensions: []
|
|
24
25
|
extra_rdoc_files: []
|
25
26
|
|
26
27
|
files:
|
27
|
-
- .gitignore
|
28
|
-
- .rvmrc
|
29
|
-
-
|
30
|
-
-
|
31
|
-
-
|
32
|
-
-
|
33
|
-
-
|
34
|
-
-
|
35
|
-
-
|
36
|
-
-
|
37
|
-
-
|
38
|
-
- lib/
|
39
|
-
- lib/
|
40
|
-
- lib/hot_bunnies
|
41
|
-
- lib/hot_bunnies/
|
28
|
+
- .gitignore
|
29
|
+
- .rvmrc
|
30
|
+
- .travis.yml
|
31
|
+
- Gemfile
|
32
|
+
- LICENSE
|
33
|
+
- README.md
|
34
|
+
- Rakefile
|
35
|
+
- examples/blocking_subscription.rb
|
36
|
+
- examples/non_blocking_subscription.rb
|
37
|
+
- examples/non_blocking_subscription_with_executor.rb
|
38
|
+
- hot_bunnies.gemspec
|
39
|
+
- lib/ext/commons-io.jar
|
40
|
+
- lib/ext/rabbitmq-client.jar
|
41
|
+
- lib/hot_bunnies.rb
|
42
|
+
- lib/hot_bunnies/channel.rb
|
43
|
+
- lib/hot_bunnies/exchange.rb
|
44
|
+
- lib/hot_bunnies/queue.rb
|
45
|
+
- lib/hot_bunnies/version.rb
|
46
|
+
- spec/integration/alternate_exchanges_spec.rb
|
47
|
+
- spec/integration/exchange_bind_spec.rb
|
48
|
+
- spec/integration/exchange_declare_spec.rb
|
49
|
+
- spec/integration/publisher_confirmations_spec.rb
|
50
|
+
- spec/integration/queue_bind_spec.rb
|
51
|
+
- spec/integration/queue_declare_spec.rb
|
52
|
+
- spec/integration/queue_delete_spec.rb
|
53
|
+
- spec/integration/queue_purge_spec.rb
|
54
|
+
- spec/integration/queue_unbind_spec.rb
|
55
|
+
- spec/integration/sender_selected_distribution_spec.rb
|
56
|
+
- spec/spec_helper.rb
|
42
57
|
has_rdoc: true
|
43
58
|
homepage: http://github.com/iconara/hot_bunnies
|
44
59
|
licenses: []
|
@@ -47,23 +62,23 @@ post_install_message:
|
|
47
62
|
rdoc_options: []
|
48
63
|
|
49
64
|
require_paths:
|
50
|
-
- lib
|
65
|
+
- lib
|
51
66
|
required_ruby_version: !ruby/object:Gem::Requirement
|
52
67
|
none: false
|
53
68
|
requirements:
|
54
|
-
|
55
|
-
|
56
|
-
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: "0"
|
57
72
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
73
|
none: false
|
59
74
|
requirements:
|
60
|
-
|
61
|
-
|
62
|
-
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: "0"
|
63
78
|
requirements: []
|
64
79
|
|
65
80
|
rubyforge_project: hot_bunnies
|
66
|
-
rubygems_version: 1.5.
|
81
|
+
rubygems_version: 1.5.1
|
67
82
|
signing_key:
|
68
83
|
specification_version: 3
|
69
84
|
summary: Ruby wrapper for the RabbitMQ Java driver
|