rosetta_queue 0.4.0 → 0.5.0
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/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
|