rosetta_queue 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +9 -3
- data/VERSION.yml +3 -2
- data/features/support/tmp/barconsumer.log +0 -0
- data/features/support/tmp/fooconsumer.log +0 -0
- data/features/support/tmp/point-to-point.log +0 -0
- data/features/support/tmp/pub-sub.log +0 -0
- data/lib/rosetta_queue.rb +0 -1
- data/lib/rosetta_queue/adapter.rb +14 -2
- data/lib/rosetta_queue/adapters/amqp.rb +44 -6
- data/lib/rosetta_queue/adapters/amqp_evented.rb +16 -30
- data/lib/rosetta_queue/adapters/amqp_synch.rb +4 -24
- data/lib/rosetta_queue/adapters/fake.rb +10 -1
- data/lib/rosetta_queue/adapters/null.rb +2 -2
- data/lib/rosetta_queue/adapters/stomp.rb +18 -29
- data/lib/rosetta_queue/consumer.rb +10 -4
- data/lib/rosetta_queue/consumer_managers/base.rb +1 -2
- data/lib/rosetta_queue/consumer_managers/evented.rb +1 -0
- data/lib/rosetta_queue/producer.rb +7 -5
- data/spec/rosetta_queue/adapter_spec.rb +52 -8
- data/spec/rosetta_queue/adapters/amqp_synchronous_spec.rb +27 -1
- data/spec/rosetta_queue/adapters/shared_adapter_behavior.rb +7 -0
- data/spec/rosetta_queue/adapters/stomp_spec.rb +31 -25
- data/spec/rosetta_queue/consumer_managers/base_spec.rb +36 -0
- data/spec/rosetta_queue/consumer_spec.rb +5 -6
- data/spec/rosetta_queue/producer_spec.rb +4 -24
- data/spec/spec_helper.rb +0 -1
- metadata +9 -6
- data/lib/rosetta_queue/base.rb +0 -15
- data/spec/rosetta_queue/shared_messaging_behavior.rb +0 -21
data/History.txt
CHANGED
@@ -1,11 +1,17 @@
|
|
1
|
-
== 0.
|
1
|
+
== 0.5.0 (the "Resource Cleanup" release)
|
2
|
+
=== New Features (Relevance Inc.)
|
3
|
+
* Fixed a socket leak in Producer::publish by using open on the Adapter (at least for Stomp, but probably others too).
|
4
|
+
* Add Adapter::open, which has semantics like File::open (ie auto-disconnecting the socket after the block),
|
5
|
+
* Removed Adapter::instance due to it's confusing name (it was not a singleton as the name suggested).
|
6
|
+
* Allow specifying a key when adding handlers to a consumer, to allow multiple instances of same consumer.
|
7
|
+
* Removed dependency on message_handler when calling Adapter#disconnect. (Chris Wyckoff)
|
2
8
|
|
3
9
|
== 0.4.0
|
4
10
|
=== New features
|
5
11
|
* Allows for custom exception handling logic to be registered for publishing and consuming actions. See ExceptionHandler for more info. (Ben Mabey)
|
6
12
|
* RQ was doing a blanket rescue for publishing and consuming and then logging the errors. If you still want this behaviour you will need to register a block/class to do that. Again, see ExceptionHandler for more details.
|
7
13
|
* Added core time extension when ActiveSupport not present. (Chris Wyckoff)
|
8
|
-
===
|
14
|
+
=== Bugfixes
|
9
15
|
* Closing the connection after publishing message now instead of unsubscribing. (Chris Wyckoff)
|
10
16
|
|
11
17
|
|
@@ -16,7 +22,7 @@
|
|
16
22
|
* Added .delete method to Consumer class (Chris Wyckoff - Lead Media Partners)
|
17
23
|
* Allows user to purge a queue.
|
18
24
|
* Works for AMQP adapters only.
|
19
|
-
===
|
25
|
+
=== Bugfixes
|
20
26
|
* client :ack now working. (Chris Wyckoff - Lead Media Partners)
|
21
27
|
|
22
28
|
== 0.1.4
|
data/VERSION.yml
CHANGED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/lib/rosetta_queue.rb
CHANGED
@@ -4,7 +4,6 @@ require('rosetta_queue/core_ext/string') unless defined? ActiveSupport
|
|
4
4
|
require('rosetta_queue/core_ext/time') unless defined? ActiveSupport
|
5
5
|
|
6
6
|
require 'rosetta_queue/adapter'
|
7
|
-
require 'rosetta_queue/base'
|
8
7
|
require 'rosetta_queue/consumer'
|
9
8
|
require 'rosetta_queue/destinations'
|
10
9
|
require 'rosetta_queue/exceptions'
|
@@ -22,9 +22,21 @@ module RosettaQueue
|
|
22
22
|
raise AdapterException, "Adapter type '#{adapter_prefix}' does not match existing adapters!"
|
23
23
|
end
|
24
24
|
|
25
|
-
|
25
|
+
# Yield a new (connected) adapter, run whatever is in the block, and then disconnect after the
|
26
|
+
# block evaluates
|
27
|
+
def open
|
26
28
|
raise AdapterException, "Adapter type was never defined!" unless @adapter_class
|
27
|
-
@adapter_class.new({:user => @user, :password => @password, :host => @host, :port => @port, :opts => opts})
|
29
|
+
adapter = @adapter_class.new({:user => @user, :password => @password, :host => @host, :port => @port, :opts => opts})
|
30
|
+
|
31
|
+
if block_given?
|
32
|
+
begin
|
33
|
+
yield adapter
|
34
|
+
ensure
|
35
|
+
adapter.disconnect
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
adapter
|
28
40
|
end
|
29
41
|
|
30
42
|
private
|
@@ -20,13 +20,13 @@ module RosettaQueue
|
|
20
20
|
exchange_strategy_for(destination, opts).delete(destination)
|
21
21
|
end
|
22
22
|
|
23
|
-
def disconnect
|
24
|
-
|
25
|
-
exchange_strategy_for(destination).unsubscribe
|
23
|
+
def disconnect
|
24
|
+
@exchange_strategy.unsubscribe if @exchange_strategy
|
26
25
|
end
|
27
26
|
|
28
27
|
def receive_once(destination, opts={})
|
29
|
-
exchange_strategy_for(destination, opts)
|
28
|
+
@exchange_strategy = exchange_strategy_for(destination, opts)
|
29
|
+
@exchange_strategy.receive_once(destination) do |msg|
|
30
30
|
return msg
|
31
31
|
end
|
32
32
|
end
|
@@ -34,15 +34,53 @@ module RosettaQueue
|
|
34
34
|
def receive_with(message_handler)
|
35
35
|
options = options_for(message_handler)
|
36
36
|
destination = destination_for(message_handler)
|
37
|
-
exchange_strategy_for(destination, options)
|
37
|
+
@exchange_strategy = exchange_strategy_for(destination, options)
|
38
|
+
@exchange_strategy.receive(destination, message_handler)
|
38
39
|
end
|
39
40
|
|
40
41
|
def send_message(destination, message, options=nil)
|
41
|
-
exchange_strategy_for(destination, options)
|
42
|
+
@exchange_strategy = exchange_strategy_for(destination, options)
|
43
|
+
@exchange_strategy.publish(destination, message)
|
42
44
|
end
|
43
45
|
|
44
46
|
def unsubscribe; end
|
45
47
|
|
46
48
|
end
|
49
|
+
|
50
|
+
class AmqpEventedAdapter < Amqp
|
51
|
+
|
52
|
+
def exchange_strategy_for(destination, options)
|
53
|
+
case destination
|
54
|
+
when /^fanout\./
|
55
|
+
@exchange ||= EventedExchange::FanoutExchange.new(@adapter_settings, options)
|
56
|
+
when /^topic\./
|
57
|
+
raise "Sorry. RosettaQueue can not process AMQP topics yet"
|
58
|
+
when /^queue\./
|
59
|
+
@exchange ||= EventedExchange::DirectExchange.new(@adapter_settings, options)
|
60
|
+
else
|
61
|
+
@exchange ||= EventedExchange::DirectExchange.new(@adapter_settings, options)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
# This AMQP adapter utilizes the synchronous AMPQ client 'Bunny'
|
68
|
+
# by celldee (http://github.com/celldee/bunny)
|
69
|
+
class AmqpSynchAdapter < Amqp
|
70
|
+
|
71
|
+
def exchange_strategy_for(destination, options={})
|
72
|
+
case destination
|
73
|
+
when /^fanout\./
|
74
|
+
@exchange ||= SynchExchange::FanoutExchange.new(@adapter_settings, options)
|
75
|
+
when /^topic\./
|
76
|
+
raise "Sorry. RosettaQueue can not process AMQP topics yet"
|
77
|
+
when /^queue\./
|
78
|
+
@exchange ||= SynchExchange::DirectExchange.new(@adapter_settings, options)
|
79
|
+
else
|
80
|
+
@exchange ||= SynchExchange::DirectExchange.new(@adapter_settings, options)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
47
85
|
end
|
48
86
|
end
|
@@ -5,23 +5,6 @@ require File.expand_path(File.dirname(__FILE__) + "/amqp.rb")
|
|
5
5
|
module RosettaQueue
|
6
6
|
module Gateway
|
7
7
|
|
8
|
-
class AmqpEventedAdapter < Amqp
|
9
|
-
private
|
10
|
-
|
11
|
-
def exchange_strategy_for(destination, options)
|
12
|
-
case destination
|
13
|
-
when /^fanout\./
|
14
|
-
@exchange ||= EventedExchange::FanoutExchange.new(@adapter_settings, options)
|
15
|
-
when /^topic\./
|
16
|
-
raise "Sorry. RosettaQueue can not process AMQP topics yet"
|
17
|
-
when /^queue\./
|
18
|
-
@exchange ||= EventedExchange::DirectExchange.new(@adapter_settings, options)
|
19
|
-
else
|
20
|
-
@exchange ||= EventedExchange::DirectExchange.new(@adapter_settings, options)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
8
|
module EventedExchange
|
26
9
|
|
27
10
|
class BaseExchange
|
@@ -34,6 +17,10 @@ module RosettaQueue
|
|
34
17
|
conn.queue(destination).delete(@options)
|
35
18
|
end
|
36
19
|
|
20
|
+
def unsubscribe
|
21
|
+
@queue.unsubscribe if @queue
|
22
|
+
end
|
23
|
+
|
37
24
|
protected
|
38
25
|
|
39
26
|
def channel
|
@@ -55,18 +42,17 @@ module RosettaQueue
|
|
55
42
|
def publish(destination, message, options={})
|
56
43
|
raise AdapterException, "Messages need to be published in an EventMachine run block (e.g., EM.run { RosettaQueue::Producer.publish(:foo, msg) } " unless EM.reactor_running?
|
57
44
|
|
58
|
-
queue = channel.queue(destination, options)
|
59
|
-
queue.publish(message, options)
|
45
|
+
@queue = channel.queue(destination, options)
|
46
|
+
@queue.publish(message, options)
|
60
47
|
RosettaQueue.logger.info("Publishing to #{destination} :: #{message}")
|
61
|
-
queue.unsubscribe
|
62
48
|
end
|
63
49
|
|
64
50
|
def receive(destination, message_handler)
|
65
51
|
raise AdapterException, "Consumers need to run in an EventMachine 'run' block. Try wrapping them inside the evented consumer manager." unless EM.reactor_running?
|
66
52
|
|
67
|
-
queue = channel.queue(destination, @options)
|
53
|
+
@queue = channel.queue(destination, @options)
|
68
54
|
ack = @options[:ack]
|
69
|
-
queue.subscribe(@options) do |header, msg|
|
55
|
+
@queue.subscribe(@options) do |header, msg|
|
70
56
|
RosettaQueue.logger.info("Receiving from #{destination} :: #{msg}")
|
71
57
|
message_handler.handle_message(msg)
|
72
58
|
header.ack if ack
|
@@ -76,9 +62,9 @@ module RosettaQueue
|
|
76
62
|
def receive_once(destination, options={})
|
77
63
|
raise AdapterException, "Consumers need to run in an EventMachine 'run' block. (e.g., EM.run { RosettaQueue::Consumer.receive }" unless EM.reactor_running?
|
78
64
|
|
79
|
-
queue = channel.queue(destination, @options)
|
65
|
+
@queue = channel.queue(destination, @options)
|
80
66
|
ack = @options[:ack]
|
81
|
-
queue.pop(@options) do |header, msg|
|
67
|
+
@queue.pop(@options) do |header, msg|
|
82
68
|
RosettaQueue.logger.info("Receiving from #{destination} :: #{msg}")
|
83
69
|
header.ack if ack
|
84
70
|
yield Filters.process_receiving(msg)
|
@@ -93,19 +79,19 @@ module RosettaQueue
|
|
93
79
|
def publish(dest, msg, opts)
|
94
80
|
raise AdapterException, "Messages need to be published in an EventMachine run block (e.g., EM.run { RosettaQueue::Producer.publish(:foo, msg) } " unless EM.reactor_running?
|
95
81
|
|
96
|
-
|
97
|
-
|
82
|
+
@queue = channel.fanout(fanout_name_for(dest), opts)
|
83
|
+
@queue.publish(msg, opts)
|
98
84
|
RosettaQueue.logger.info("Publishing to fanout #{dest} :: #{msg}")
|
99
85
|
end
|
100
86
|
|
101
87
|
def receive(destination, message_handler)
|
102
88
|
raise AdapterException, "Consumers need to run in an EventMachine 'run' block. Try wrapping them inside the evented consumer manager." unless EM.reactor_running?
|
103
89
|
|
104
|
-
queue = channel.queue("queue_#{self.object_id}")
|
90
|
+
@queue = channel.queue("queue_#{self.object_id}")
|
105
91
|
exchange = channel.fanout(fanout_name_for(destination), @options)
|
106
92
|
ack = @options[:ack]
|
107
93
|
|
108
|
-
queue.bind(exchange).subscribe(@options) do |header, msg|
|
94
|
+
@queue.bind(exchange).subscribe(@options) do |header, msg|
|
109
95
|
RosettaQueue.logger.info("Receiving from #{destination} :: #{msg}")
|
110
96
|
message_handler.handle_message(msg)
|
111
97
|
header.ack if ack
|
@@ -115,11 +101,11 @@ module RosettaQueue
|
|
115
101
|
def receive_once(destination, opts={})
|
116
102
|
raise AdapterException, "Consumers need to run in an EventMachine 'run' block. (e.g., EM.run { RosettaQueue::Consumer.receive }" unless EM.reactor_running?
|
117
103
|
|
118
|
-
queue = channel.queue("queue_#{self.object_id}")
|
104
|
+
@queue = channel.queue("queue_#{self.object_id}")
|
119
105
|
exchange = channel.fanout(fanout_name_for(destination), opts)
|
120
106
|
ack = @options[:ack]
|
121
107
|
|
122
|
-
queue.bind(exchange).pop(opts) do |header, msg|
|
108
|
+
@queue.bind(exchange).pop(opts) do |header, msg|
|
123
109
|
RosettaQueue.logger.info("Receiving from #{destination} :: #{msg}")
|
124
110
|
header.ack if ack
|
125
111
|
yield Filters.process_receiving(msg)
|
@@ -4,25 +4,6 @@ require File.expand_path(File.dirname(__FILE__) + "/amqp.rb")
|
|
4
4
|
module RosettaQueue
|
5
5
|
module Gateway
|
6
6
|
|
7
|
-
# This AMQP adapter utilizes the synchronous AMPQ client 'Bunny'
|
8
|
-
# by celldee (http://github.com/celldee/bunny)
|
9
|
-
class AmqpSynchAdapter < Amqp
|
10
|
-
private
|
11
|
-
|
12
|
-
def exchange_strategy_for(destination, options={})
|
13
|
-
case destination
|
14
|
-
when /^fanout\./
|
15
|
-
@exchange ||= SynchExchange::FanoutExchange.new(@adapter_settings, options)
|
16
|
-
when /^topic\./
|
17
|
-
raise "Sorry. RosettaQueue can not process AMQP topics yet"
|
18
|
-
when /^queue\./
|
19
|
-
@exchange ||= SynchExchange::DirectExchange.new(@adapter_settings, options)
|
20
|
-
else
|
21
|
-
@exchange ||= SynchExchange::DirectExchange.new(@adapter_settings, options)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
7
|
module SynchExchange
|
27
8
|
|
28
9
|
class BaseExchange
|
@@ -58,9 +39,8 @@ module RosettaQueue
|
|
58
39
|
|
59
40
|
def publish(destination, message, options={})
|
60
41
|
RosettaQueue.logger.info("Publishing to #{destination} :: #{message}")
|
61
|
-
queue = conn.queue(destination, options)
|
62
|
-
queue.publish(message, options)
|
63
|
-
conn.stop
|
42
|
+
@queue = conn.queue(destination, options)
|
43
|
+
@queue.publish(message, options)
|
64
44
|
end
|
65
45
|
|
66
46
|
def receive(destination, message_handler)
|
@@ -88,8 +68,8 @@ module RosettaQueue
|
|
88
68
|
include Fanout
|
89
69
|
|
90
70
|
def publish(destination, message, options={})
|
91
|
-
|
92
|
-
|
71
|
+
@queue = conn.exchange(fanout_name_for(destination), options.merge({:type => :fanout}))
|
72
|
+
@queue.publish(message, options)
|
93
73
|
RosettaQueue.logger.info("Publishing to fanout #{destination} :: #{message}")
|
94
74
|
end
|
95
75
|
|
@@ -3,8 +3,9 @@ module RosettaQueue
|
|
3
3
|
|
4
4
|
class FakeAdapter
|
5
5
|
|
6
|
-
def initialize
|
6
|
+
def initialize(adapter_settings = {})
|
7
7
|
@messages = []
|
8
|
+
@open = true
|
8
9
|
end
|
9
10
|
|
10
11
|
def send_message(queue, message, headers)
|
@@ -19,6 +20,14 @@ module RosettaQueue
|
|
19
20
|
@messages.map {|message| message['queue']}
|
20
21
|
end
|
21
22
|
|
23
|
+
def disconnect
|
24
|
+
@open = false
|
25
|
+
end
|
26
|
+
|
27
|
+
def open?
|
28
|
+
@open == true
|
29
|
+
end
|
30
|
+
|
22
31
|
end
|
23
32
|
|
24
33
|
end
|
@@ -32,11 +32,11 @@ module RosettaQueue
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def receive
|
35
|
-
raise "Null
|
35
|
+
raise "Null Adapter is in use, you can not consume messages!"
|
36
36
|
end
|
37
37
|
|
38
38
|
def receive_with(message_handler)
|
39
|
-
raise "Null
|
39
|
+
raise "Null Adapter is in use, you can not consume messages!"
|
40
40
|
end
|
41
41
|
|
42
42
|
def send_message(queue, message, options)
|
@@ -19,8 +19,8 @@ module RosettaQueue
|
|
19
19
|
true)
|
20
20
|
end
|
21
21
|
|
22
|
-
def disconnect
|
23
|
-
unsubscribe
|
22
|
+
def disconnect
|
23
|
+
unsubscribe if @destination
|
24
24
|
@conn.disconnect
|
25
25
|
end
|
26
26
|
|
@@ -31,38 +31,38 @@ module RosettaQueue
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def receive_once(destination, opts)
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
34
|
+
@destination, @options = destination, opts
|
35
|
+
subscribe
|
36
|
+
msg = receive(@options).body
|
37
|
+
unsubscribe
|
38
|
+
RosettaQueue.logger.info("Receiving from #{@destination} :: #{msg}")
|
38
39
|
filter_receiving(msg)
|
39
40
|
end
|
40
41
|
|
41
42
|
def receive_with(message_handler)
|
42
|
-
options = options_for(message_handler)
|
43
|
-
|
44
|
-
@conn.subscribe(destination, options)
|
45
|
-
|
43
|
+
@destination, @options = destination_for(message_handler), options_for(message_handler)
|
44
|
+
subscribe
|
46
45
|
running do
|
47
|
-
msg = receive(options).body
|
46
|
+
msg = receive(@options).body
|
48
47
|
Thread.current[:processing] = true
|
49
|
-
RosettaQueue.logger.info("Receiving from #{destination} :: #{msg}")
|
48
|
+
RosettaQueue.logger.info("Receiving from #{@destination} :: #{msg}")
|
50
49
|
message_handler.handle_message(msg)
|
51
50
|
Thread.current[:processing] = false
|
52
51
|
end
|
53
52
|
end
|
54
53
|
|
55
54
|
def send_message(destination, message, options)
|
56
|
-
|
57
|
-
|
55
|
+
@destination = destination
|
56
|
+
RosettaQueue.logger.info("Publishing to #{@destination} :: #{message}")
|
57
|
+
@conn.send(@destination, message, options)
|
58
58
|
end
|
59
59
|
|
60
|
-
def subscribe
|
61
|
-
@conn.subscribe(destination, options)
|
60
|
+
def subscribe
|
61
|
+
@conn.subscribe(@destination, @options)
|
62
62
|
end
|
63
63
|
|
64
|
-
def unsubscribe
|
65
|
-
@conn.unsubscribe(destination)
|
64
|
+
def unsubscribe
|
65
|
+
@conn.unsubscribe(@destination)
|
66
66
|
end
|
67
67
|
|
68
68
|
private
|
@@ -73,16 +73,5 @@ module RosettaQueue
|
|
73
73
|
|
74
74
|
end
|
75
75
|
|
76
|
-
class StompAdapterProxy
|
77
|
-
|
78
|
-
def initialize(adapter, msg)
|
79
|
-
@adapter, @msg = adapter, msg
|
80
|
-
end
|
81
|
-
|
82
|
-
def ack
|
83
|
-
@adapter.ack(@msg)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
76
|
end
|
88
77
|
end
|
@@ -1,15 +1,15 @@
|
|
1
1
|
module RosettaQueue
|
2
|
-
class Consumer
|
2
|
+
class Consumer
|
3
3
|
|
4
4
|
def self.receive(destination, options = {})
|
5
|
-
RosettaQueue::Adapter.
|
5
|
+
RosettaQueue::Adapter.open { |a| return a.receive_once(Destinations.lookup(destination), options) }
|
6
6
|
|
7
|
-
|
7
|
+
rescue Exception=>e
|
8
8
|
RosettaQueue.logger.error("Caught exception in Consumer.receive: #{$!}\n" + e.backtrace.join("\n\t"))
|
9
9
|
end
|
10
10
|
|
11
11
|
def self.delete(destination, options={})
|
12
|
-
RosettaQueue::Adapter.
|
12
|
+
RosettaQueue::Adapter.open { |a| a.delete(Destinations.lookup(destination), options)}
|
13
13
|
|
14
14
|
rescue Exception=>e
|
15
15
|
RosettaQueue.logger.error("Caught exception in Consumer.delete: #{$!}\n" + e.backtrace.join("\n\t"))
|
@@ -26,5 +26,11 @@ module RosettaQueue
|
|
26
26
|
RosettaQueue.logger.error("Caught exception in Consumer#receive: #{$!}\n" + e.backtrace.join("\n\t"))
|
27
27
|
end
|
28
28
|
|
29
|
+
private
|
30
|
+
|
31
|
+
def connection
|
32
|
+
@conn ||= Adapter.open
|
33
|
+
end
|
34
|
+
|
29
35
|
end
|
30
36
|
end
|
@@ -15,8 +15,7 @@ module RosettaQueue
|
|
15
15
|
@consumers = {}
|
16
16
|
end
|
17
17
|
|
18
|
-
def add(message_handler)
|
19
|
-
key = message_handler.class.to_s.underscore.to_sym
|
18
|
+
def add(message_handler, key = message_handler.class.to_s.underscore.to_sym)
|
20
19
|
@consumers[key] = Consumer.new(message_handler)
|
21
20
|
end
|
22
21
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module RosettaQueue
|
2
2
|
|
3
|
-
class Producer
|
3
|
+
class Producer
|
4
4
|
include MessageHandler
|
5
5
|
|
6
6
|
def self.publish(destination, message, options = {})
|
@@ -11,10 +11,12 @@ module RosettaQueue
|
|
11
11
|
:destination => destination,
|
12
12
|
:options => options}
|
13
13
|
}) do
|
14
|
-
RosettaQueue::Adapter.
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
RosettaQueue::Adapter.open do |a|
|
15
|
+
a.send_message(
|
16
|
+
Destinations.lookup(destination),
|
17
|
+
Filters.process_sending(message),
|
18
|
+
options)
|
19
|
+
end
|
18
20
|
end
|
19
21
|
end
|
20
22
|
end
|
@@ -12,9 +12,9 @@ module RosettaQueue
|
|
12
12
|
describe ".reset" do
|
13
13
|
it "should clear all definitions" do
|
14
14
|
Adapter.define { |a| a.type = "null" }
|
15
|
-
Adapter.
|
15
|
+
Adapter.open.should be_instance_of(RosettaQueue::Gateway::NullAdapter)
|
16
16
|
Adapter.reset
|
17
|
-
running { Adapter.
|
17
|
+
running { Adapter.open }.should raise_error(AdapterException)
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
@@ -31,11 +31,11 @@ module RosettaQueue
|
|
31
31
|
end
|
32
32
|
|
33
33
|
describe "adapter not type set" do
|
34
|
-
it "should raise an error when .
|
34
|
+
it "should raise an error when .open is called" do
|
35
35
|
# given
|
36
36
|
Adapter.define { |a| }
|
37
37
|
# then & when
|
38
|
-
running { Adapter.
|
38
|
+
running { Adapter.open }.should raise_error(AdapterException)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -45,8 +45,8 @@ module RosettaQueue
|
|
45
45
|
Adapter.define { |a| a.type = "null" }
|
46
46
|
end
|
47
47
|
|
48
|
-
it "should return adapter
|
49
|
-
Adapter.
|
48
|
+
it "should return adapter open" do
|
49
|
+
Adapter.open.class.should == RosettaQueue::Gateway::NullAdapter
|
50
50
|
end
|
51
51
|
|
52
52
|
end
|
@@ -64,7 +64,7 @@ module RosettaQueue
|
|
64
64
|
end
|
65
65
|
|
66
66
|
def do_process
|
67
|
-
Adapter.
|
67
|
+
Adapter.open
|
68
68
|
end
|
69
69
|
|
70
70
|
it "should set opts as an empty has unless variable is set" do
|
@@ -92,10 +92,54 @@ module RosettaQueue
|
|
92
92
|
end
|
93
93
|
|
94
94
|
it "should raise an adapter exception" do
|
95
|
-
running { Adapter.
|
95
|
+
running { Adapter.open }.should raise_error("Adapter options should be a hash")
|
96
96
|
end
|
97
97
|
end
|
98
98
|
|
99
99
|
end
|
100
|
+
|
101
|
+
describe ".open" do
|
102
|
+
|
103
|
+
before(:each) do
|
104
|
+
Adapter.define do |a|
|
105
|
+
a.user = "foo"
|
106
|
+
a.password = "bar"
|
107
|
+
a.host = "localhost"
|
108
|
+
a.port = "9000"
|
109
|
+
a.type = "fake"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
it "returns an open adapter if no block is given" do
|
114
|
+
adapter = Adapter.open
|
115
|
+
adapter.should be_open
|
116
|
+
end
|
117
|
+
|
118
|
+
it "yields a newly-instantiated adapter to the block" do
|
119
|
+
ran_block = false
|
120
|
+
|
121
|
+
Adapter.open do |a|
|
122
|
+
a.should_not be_nil
|
123
|
+
a.should be_instance_of(RosettaQueue::Gateway::FakeAdapter)
|
124
|
+
a.should be_open
|
125
|
+
ran_block = true
|
126
|
+
end
|
127
|
+
|
128
|
+
ran_block.should be_true
|
129
|
+
end
|
130
|
+
|
131
|
+
it "closes the adapter after the block is evaluated" do
|
132
|
+
Adapter.open {|a| "something" }.should_not be_open
|
133
|
+
end
|
134
|
+
|
135
|
+
it "closes the adapter even if the block raises an error" do
|
136
|
+
adapter = nil
|
137
|
+
begin
|
138
|
+
Adapter.open {|a| adapter = a; raise("some connection error here!") }
|
139
|
+
rescue => e;
|
140
|
+
end
|
141
|
+
adapter.should_not be_open
|
142
|
+
end
|
143
|
+
end
|
100
144
|
end
|
101
145
|
end
|
@@ -87,9 +87,35 @@ module RosettaQueue::Gateway
|
|
87
87
|
end
|
88
88
|
|
89
89
|
end
|
90
|
-
end
|
91
90
|
|
91
|
+
describe "#disconnect" do
|
92
|
+
|
93
|
+
it "delegates to cached exchange strategy" do
|
94
|
+
# given
|
95
|
+
@adapter.receive_with(@handler)
|
96
|
+
|
97
|
+
# expect
|
98
|
+
@exchange_strategy.should_receive(:unsubscribe)
|
99
|
+
|
100
|
+
# when
|
101
|
+
@adapter.disconnect
|
102
|
+
end
|
103
|
+
|
104
|
+
context "subscription was never made" do
|
105
|
+
|
106
|
+
it "does not delegate to exchange strategy" do
|
107
|
+
# expect
|
108
|
+
@exchange_strategy.should_not_receive(:unsubscribe)
|
92
109
|
|
110
|
+
# when
|
111
|
+
@adapter.disconnect
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
93
119
|
describe SynchExchange::DirectExchange do
|
94
120
|
|
95
121
|
before(:each) do
|
@@ -83,42 +83,48 @@ module RosettaQueue
|
|
83
83
|
|
84
84
|
describe "disconnect" do
|
85
85
|
|
86
|
-
|
87
|
-
@adapter.disconnect(@handler)
|
88
|
-
end
|
86
|
+
describe "simple disconnection without previously subscribing" do
|
89
87
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
}
|
94
|
-
end
|
95
|
-
|
96
|
-
it "should disconnect connection" do
|
97
|
-
when_disconnecting {
|
98
|
-
@conn.should_receive("disconnect")
|
99
|
-
}
|
100
|
-
end
|
88
|
+
def do_disconnecting
|
89
|
+
@adapter.disconnect
|
90
|
+
end
|
101
91
|
|
102
|
-
|
92
|
+
it "should NOT try to unsubscribe the connection" do
|
93
|
+
when_disconnecting {
|
94
|
+
@conn.should_receive("unsubscribe").never
|
95
|
+
}
|
96
|
+
end
|
103
97
|
|
104
|
-
|
98
|
+
it "should disconnect connection" do
|
99
|
+
when_disconnecting {
|
100
|
+
@conn.should_receive("disconnect")
|
101
|
+
}
|
102
|
+
end
|
105
103
|
|
106
|
-
before(:each) do
|
107
|
-
@adapter = mock("StompAdapter", :ack => nil)
|
108
|
-
@proxy = StompAdapterProxy.new(@adapter, "foo")
|
109
104
|
end
|
110
105
|
|
111
|
-
|
106
|
+
describe "when given a previously-subscribed message handler to unsubscribe from" do
|
112
107
|
|
113
|
-
|
114
|
-
|
115
|
-
@adapter.
|
108
|
+
def do_disconnecting
|
109
|
+
@adapter.receive_with(@handler)
|
110
|
+
@adapter.disconnect
|
111
|
+
end
|
116
112
|
|
117
|
-
|
118
|
-
|
113
|
+
it "should unsubscribe connection" do
|
114
|
+
when_disconnecting {
|
115
|
+
@conn.should_receive("unsubscribe").with("foo")
|
116
|
+
}
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should disconnect connection" do
|
120
|
+
when_disconnecting {
|
121
|
+
@conn.should_receive("disconnect")
|
122
|
+
}
|
119
123
|
end
|
120
124
|
|
121
125
|
end
|
126
|
+
|
127
|
+
|
122
128
|
end
|
123
129
|
|
124
130
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
module RosettaQueue
|
4
|
+
describe BaseManager do
|
5
|
+
|
6
|
+
describe "#add" do
|
7
|
+
it "allows adding a handler" do
|
8
|
+
BaseManager.new.add(Object.new)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "wraps the handler with a consumer and stores it" do
|
12
|
+
handler = Object.new
|
13
|
+
Consumer.should_receive(:new).with(handler)
|
14
|
+
BaseManager.new.add(handler)
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "storing the consumer" do
|
18
|
+
it "uses the class name as the key by default" do
|
19
|
+
handler = Object.new
|
20
|
+
manager = BaseManager.new
|
21
|
+
manager.add(handler)
|
22
|
+
manager.consumers.keys.should == [:object]
|
23
|
+
end
|
24
|
+
|
25
|
+
it "allows overriding the key name for cases where you have multiple instances of the same handler class" do
|
26
|
+
handler = Object.new
|
27
|
+
manager = BaseManager.new
|
28
|
+
manager.add(handler, :object_1)
|
29
|
+
manager.add(handler, :object_2)
|
30
|
+
manager.consumers.keys.should =~ [:object_1, :object_2]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -16,14 +16,12 @@ module RosettaQueue
|
|
16
16
|
|
17
17
|
before(:each) do
|
18
18
|
@message = mock("message", "headers" => "foo", "body" => "message body")
|
19
|
-
@adapter = mock("
|
19
|
+
@adapter = mock("adapter", :subscribe => true, :unsubscribe => true, :disconnect => true, :receive_with => TestConsumer.new,
|
20
20
|
:receive_once => @message.body, :ack => true)
|
21
|
-
Adapter.stub!(:
|
21
|
+
Adapter.stub!(:open).and_yield(@adapter)
|
22
22
|
Destinations.stub!(:lookup).and_return("/queue/foo")
|
23
23
|
end
|
24
24
|
|
25
|
-
it_should_behave_like "a messaging gateway object"
|
26
|
-
|
27
25
|
attr_reader :adapter
|
28
26
|
def gateway
|
29
27
|
@gateway ||= Consumer.new(TestConsumer.new)
|
@@ -39,9 +37,10 @@ module RosettaQueue
|
|
39
37
|
@consumer.receive
|
40
38
|
end
|
41
39
|
|
42
|
-
it "should pass message handler onto the
|
40
|
+
it "should pass message handler onto the adapter with #receive" do
|
41
|
+
Adapter.stub!(:open).and_return(@adapter)
|
43
42
|
when_receiving {
|
44
|
-
@adapter.should_receive(
|
43
|
+
@adapter.should_receive(:receive_with).with(@message_handler)
|
45
44
|
}
|
46
45
|
end
|
47
46
|
end
|
@@ -12,44 +12,24 @@ module RosettaQueue
|
|
12
12
|
describe Producer do
|
13
13
|
|
14
14
|
before(:each) do
|
15
|
-
@adapter = mock("adapter", :send_message => nil)
|
16
|
-
RosettaQueue::Adapter.stub!(:
|
15
|
+
@adapter = mock("adapter", :send_message => nil, :disconnect => nil)
|
16
|
+
RosettaQueue::Adapter.stub!(:open).and_yield(@adapter)
|
17
17
|
@gateway = TestProducer.new
|
18
18
|
|
19
19
|
Destinations.stub!(:lookup).and_return("/queue/test_queue")
|
20
20
|
end
|
21
21
|
|
22
|
-
it_should_behave_like "a messaging gateway object"
|
23
22
|
attr_reader :adapter, :gateway
|
24
23
|
|
25
|
-
|
26
|
-
describe "#publish" do
|
27
|
-
|
28
|
-
before(:each) do
|
29
|
-
@adapter = mock("adpater", :send_message => nil)
|
30
|
-
RosettaQueue::Adapter.stub!(:instance).and_return(@adapter)
|
31
|
-
end
|
32
|
-
|
33
|
-
it "should publish messages to queue with the options defined in the class" do
|
34
|
-
# TO DO: REFACTOR #publish METHOD SO THAT YOU PASS IN MESSAGE HANDLER AS WITH CONSUMER
|
35
|
-
pending
|
36
|
-
# expect
|
37
|
-
@adapter.should_receive(:send_message).with("/queue/test_queue", "Hello World!", {:persistent => false})
|
38
|
-
# when
|
39
|
-
@gateway.publish("Hello World!")
|
40
|
-
end
|
41
|
-
|
42
|
-
end
|
43
|
-
|
44
24
|
describe ".publish" do
|
45
|
-
it "should send the message to the
|
25
|
+
it "should send the message to the adapter along with the options" do
|
46
26
|
# expect
|
47
27
|
@adapter.should_receive(:send_message).with("/queue/test_queue", "Hello World!", {:persistent => true})
|
48
28
|
# when
|
49
29
|
Producer.publish(:test_queue, "Hello World!", {:persistent => true})
|
50
30
|
end
|
51
31
|
|
52
|
-
it "
|
32
|
+
it "delegates exception handling to the ExceptionHandler for :publishing" do
|
53
33
|
ExceptionHandler.should_receive(:handle).with(:publishing, anything)
|
54
34
|
Producer.publish(:test_queue, "Hello World!", {:persistent => true})
|
55
35
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -17,7 +17,6 @@ require 'rosetta_queue/spec_helpers'
|
|
17
17
|
require 'rosetta_queue/consumer_managers/base'
|
18
18
|
require 'rosetta_queue/consumer_managers/evented'
|
19
19
|
require 'rosetta_queue/consumer_managers/threaded'
|
20
|
-
require File.dirname(__FILE__) + '/rosetta_queue/shared_messaging_behavior.rb'
|
21
20
|
|
22
21
|
class NullLogger
|
23
22
|
def info(*args); end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rosetta_queue
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Mabey
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2009-
|
13
|
+
date: 2009-12-21 00:00:00 -07:00
|
14
14
|
default_executable:
|
15
15
|
dependencies: []
|
16
16
|
|
@@ -38,6 +38,10 @@ files:
|
|
38
38
|
- features/step_definitions/publish_subscribe_steps.rb
|
39
39
|
- features/support/env.rb
|
40
40
|
- features/support/sample_consumers.rb
|
41
|
+
- features/support/tmp/barconsumer.log
|
42
|
+
- features/support/tmp/fooconsumer.log
|
43
|
+
- features/support/tmp/point-to-point.log
|
44
|
+
- features/support/tmp/pub-sub.log
|
41
45
|
- lib/rosetta_queue.rb
|
42
46
|
- lib/rosetta_queue/adapter.rb
|
43
47
|
- lib/rosetta_queue/adapters/amqp.rb
|
@@ -48,7 +52,6 @@ files:
|
|
48
52
|
- lib/rosetta_queue/adapters/fake.rb
|
49
53
|
- lib/rosetta_queue/adapters/null.rb
|
50
54
|
- lib/rosetta_queue/adapters/stomp.rb
|
51
|
-
- lib/rosetta_queue/base.rb
|
52
55
|
- lib/rosetta_queue/consumer.rb
|
53
56
|
- lib/rosetta_queue/consumer_managers/base.rb
|
54
57
|
- lib/rosetta_queue/consumer_managers/evented.rb
|
@@ -74,6 +77,7 @@ files:
|
|
74
77
|
- spec/rosetta_queue/adapters/shared_adapter_behavior.rb
|
75
78
|
- spec/rosetta_queue/adapters/shared_fanout_behavior.rb
|
76
79
|
- spec/rosetta_queue/adapters/stomp_spec.rb
|
80
|
+
- spec/rosetta_queue/consumer_managers/base_spec.rb
|
77
81
|
- spec/rosetta_queue/consumer_managers/evented_spec.rb
|
78
82
|
- spec/rosetta_queue/consumer_managers/shared_manager_behavior.rb
|
79
83
|
- spec/rosetta_queue/consumer_managers/threaded_spec.rb
|
@@ -84,7 +88,6 @@ files:
|
|
84
88
|
- spec/rosetta_queue/filters_spec.rb
|
85
89
|
- spec/rosetta_queue/message_handler_spec.rb
|
86
90
|
- spec/rosetta_queue/producer_spec.rb
|
87
|
-
- spec/rosetta_queue/shared_messaging_behavior.rb
|
88
91
|
- spec/spec.opts
|
89
92
|
- spec/spec_helper.rb
|
90
93
|
has_rdoc: true
|
@@ -111,7 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
111
114
|
requirements: []
|
112
115
|
|
113
116
|
rubyforge_project: rosetta-queue
|
114
|
-
rubygems_version: 1.3.
|
117
|
+
rubygems_version: 1.3.5
|
115
118
|
signing_key:
|
116
119
|
specification_version: 3
|
117
120
|
summary: Messaging gateway API with adapters for many messaging systems available in Ruby.
|
@@ -124,6 +127,7 @@ test_files:
|
|
124
127
|
- spec/rosetta_queue/adapters/shared_adapter_behavior.rb
|
125
128
|
- spec/rosetta_queue/adapters/shared_fanout_behavior.rb
|
126
129
|
- spec/rosetta_queue/adapters/stomp_spec.rb
|
130
|
+
- spec/rosetta_queue/consumer_managers/base_spec.rb
|
127
131
|
- spec/rosetta_queue/consumer_managers/evented_spec.rb
|
128
132
|
- spec/rosetta_queue/consumer_managers/shared_manager_behavior.rb
|
129
133
|
- spec/rosetta_queue/consumer_managers/threaded_spec.rb
|
@@ -134,7 +138,6 @@ test_files:
|
|
134
138
|
- spec/rosetta_queue/filters_spec.rb
|
135
139
|
- spec/rosetta_queue/message_handler_spec.rb
|
136
140
|
- spec/rosetta_queue/producer_spec.rb
|
137
|
-
- spec/rosetta_queue/shared_messaging_behavior.rb
|
138
141
|
- spec/spec_helper.rb
|
139
142
|
- examples/sample_amqp_consumer.rb
|
140
143
|
- examples/sample_amqp_fanout_consumer.rb
|
data/lib/rosetta_queue/base.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
module RosettaQueue
|
2
|
-
|
3
|
-
describe "a messaging gateway object", :shared => true do
|
4
|
-
|
5
|
-
it "#unsubscribe should be delegated to the adapter" do
|
6
|
-
pending
|
7
|
-
# expect
|
8
|
-
adapter.should_receive("unsubscribe")
|
9
|
-
# when
|
10
|
-
gateway.unsubscribe
|
11
|
-
end
|
12
|
-
|
13
|
-
it "#disconnect should be delegated to the adapter" do
|
14
|
-
# expect
|
15
|
-
adapter.should_receive("disconnect")
|
16
|
-
# when
|
17
|
-
gateway.disconnect
|
18
|
-
end
|
19
|
-
|
20
|
-
end
|
21
|
-
end
|