cwyckoff-rosetta_queue 0.3.0 → 0.3.3
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 +26 -3
- data/README.rdoc +4 -149
- data/Rakefile +3 -0
- data/VERSION.yml +2 -2
- data/cucumber.yml +1 -1
- data/examples/sample_amqp_consumer.rb +45 -0
- data/examples/sample_amqp_fanout_consumer.rb +52 -0
- data/examples/sample_amqp_fanout_producer.rb +18 -0
- data/examples/sample_amqp_producer.rb +16 -0
- data/features/filtering.feature +31 -0
- data/features/messaging.feature +47 -0
- data/features/step_definitions/common_messaging_steps.rb +82 -0
- data/features/step_definitions/filtering_steps.rb +17 -0
- data/features/step_definitions/point_to_point_steps.rb +22 -0
- data/features/step_definitions/publish_subscribe_steps.rb +25 -0
- data/features/support/env.rb +25 -0
- data/features/support/sample_consumers.rb +29 -0
- data/lib/rosetta_queue.rb +3 -2
- data/lib/rosetta_queue/adapter.rb +1 -1
- data/lib/rosetta_queue/adapters/amqp.rb +48 -0
- data/lib/rosetta_queue/adapters/amqp_evented.rb +132 -0
- data/lib/rosetta_queue/adapters/amqp_synch.rb +48 -69
- data/lib/rosetta_queue/adapters/beanstalk.rb +56 -0
- data/lib/rosetta_queue/adapters/stomp.rb +16 -1
- data/lib/rosetta_queue/consumer_managers/base.rb +3 -1
- data/lib/rosetta_queue/consumer_managers/threaded.rb +23 -4
- data/lib/rosetta_queue/core_ext/string.rb +22 -0
- data/lib/rosetta_queue/core_ext/time.rb +20 -0
- data/lib/rosetta_queue/filters.rb +1 -1
- data/lib/rosetta_queue/logger.rb +1 -1
- data/lib/rosetta_queue/message_handler.rb +6 -0
- data/spec/rosetta_queue/adapter_spec.rb +101 -0
- data/spec/rosetta_queue/adapters/amqp_synchronous_spec.rb +278 -0
- data/spec/rosetta_queue/adapters/beanstalk_spec.rb +47 -0
- data/spec/rosetta_queue/adapters/fake_spec.rb +72 -0
- data/spec/rosetta_queue/adapters/null_spec.rb +31 -0
- data/spec/rosetta_queue/adapters/shared_adapter_behavior.rb +38 -0
- data/spec/rosetta_queue/adapters/shared_fanout_behavior.rb +20 -0
- data/spec/rosetta_queue/adapters/stomp_spec.rb +126 -0
- data/spec/rosetta_queue/consumer_managers/evented_spec.rb +56 -0
- data/spec/rosetta_queue/consumer_managers/shared_manager_behavior.rb +26 -0
- data/spec/rosetta_queue/consumer_managers/threaded_spec.rb +51 -0
- data/spec/rosetta_queue/consumer_spec.rb +99 -0
- data/spec/rosetta_queue/core_ext/string_spec.rb +15 -0
- data/spec/rosetta_queue/destinations_spec.rb +34 -0
- data/spec/rosetta_queue/filters_spec.rb +44 -0
- data/spec/rosetta_queue/producer_spec.rb +66 -0
- data/spec/rosetta_queue/shared_messaging_behavior.rb +21 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +47 -0
- metadata +68 -19
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Then /^a (receiving|sending) filter is defined to prepend 'Foo' to all messages$/ do |filter_type|
|
|
2
|
+
RosettaQueue::Filters.reset
|
|
3
|
+
RosettaQueue::Filters.define do |f|
|
|
4
|
+
f.send(filter_type) { |message| "Foo #{message}" }
|
|
5
|
+
end
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
When /^the message on '(.+)' is consumed$/ do |queue_name|
|
|
9
|
+
# TODO
|
|
10
|
+
# @consumed_message = queue(:foo_queue).pop
|
|
11
|
+
@consumed_message = consume_once(queue_name.to_sym)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
Then /^the consumed message should equal "(.+)"$/ do |consumed_message|
|
|
15
|
+
@consumed_message.should == consumed_message
|
|
16
|
+
end
|
|
17
|
+
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Given /^a consumer is listening to queue '(.*)'$/ do |queue|
|
|
2
|
+
klass = eval_consumer_class(queue)
|
|
3
|
+
@thread = Thread.new do
|
|
4
|
+
cons = klass.new
|
|
5
|
+
case @adapter_type
|
|
6
|
+
when /evented/
|
|
7
|
+
EM.run do
|
|
8
|
+
RosettaQueue::Consumer.new(cons).receive
|
|
9
|
+
end
|
|
10
|
+
else
|
|
11
|
+
RosettaQueue::Consumer.new(cons).receive
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
Then /^the message should be consumed from '(.*)'$/ do |queue|
|
|
17
|
+
sleep 1
|
|
18
|
+
file_path = "#{CONSUMER_LOG_DIR}/point-to-point.log"
|
|
19
|
+
# sleep 1 unless File.exists?(file_path)
|
|
20
|
+
File.readlines(file_path).last.should =~ /Hello World! from #{queue.capitalize}Consumer/
|
|
21
|
+
@thread.kill
|
|
22
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
Given /^multiple consumers are listening to queue '(.*)'$/ do |queue|
|
|
2
|
+
@managers = []
|
|
3
|
+
Thread.new do
|
|
4
|
+
@managers << RosettaQueue::ThreadedManager.create do |m|
|
|
5
|
+
m.add(eval_consumer_class(queue, "fooconsumer.log", "FooConsumer").new)
|
|
6
|
+
m.start
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
Thread.new do
|
|
11
|
+
@managers << RosettaQueue::ThreadedManager.create do |m|
|
|
12
|
+
m.add(eval_consumer_class(queue, "barconsumer.log", "BarConsumer").new)
|
|
13
|
+
m.start
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
sleep 5
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
Then /^multiple messages should be consumed from '(\w+)'$/ do |queue|
|
|
20
|
+
["FooConsumer", "BarConsumer"].each do |class_name, value|
|
|
21
|
+
file_path = "#{CONSUMER_LOG_DIR}/#{class_name.downcase}.log"
|
|
22
|
+
File.readlines(file_path).last.should =~ /Hello World! from #{class_name}/
|
|
23
|
+
end
|
|
24
|
+
@managers.each {|m| m.stop_threads }
|
|
25
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
$:.unshift(File.dirname(__FILE__) + '/../../lib')
|
|
3
|
+
require 'rosetta_queue'
|
|
4
|
+
require 'rosetta_queue/spec_helpers'
|
|
5
|
+
require 'spec/expectations'
|
|
6
|
+
require 'rosetta_queue/spec_helpers'
|
|
7
|
+
|
|
8
|
+
CONSUMER_LOG_DIR = File.expand_path(File.dirname(__FILE__) + "/../support/tmp")
|
|
9
|
+
|
|
10
|
+
begin
|
|
11
|
+
RosettaQueue.logger = RosettaQueue::Logger.new(File.join(File.dirname(__FILE__), '../../../log', 'rosetta_queue.log'))
|
|
12
|
+
rescue Errno::ENOENT
|
|
13
|
+
Kernel.warn "No log directory setup at the root of rosetta_queue. Using the null logger instead."
|
|
14
|
+
class NullLogger
|
|
15
|
+
def info(*args); end
|
|
16
|
+
def debug(*args); end
|
|
17
|
+
def fatal(*args); end
|
|
18
|
+
def error(*args); end
|
|
19
|
+
def warn(*args); end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
RosettaQueue.logger = NullLogger.new
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
World(RosettaQueue::SpecHelpers)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/env.rb')
|
|
2
|
+
|
|
3
|
+
class SampleConsumer
|
|
4
|
+
include ::RosettaQueue::MessageHandler
|
|
5
|
+
subscribes_to :foo
|
|
6
|
+
options :durable => true
|
|
7
|
+
|
|
8
|
+
attr_reader :msg
|
|
9
|
+
|
|
10
|
+
def on_message(msg)
|
|
11
|
+
@msg = msg
|
|
12
|
+
puts "MESSAGE #{msg}"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class SampleConsumerTwo
|
|
19
|
+
include ::RosettaQueue::MessageHandler
|
|
20
|
+
subscribes_to :foo
|
|
21
|
+
options :durable => true
|
|
22
|
+
|
|
23
|
+
attr_reader :msg
|
|
24
|
+
|
|
25
|
+
def on_message(msg)
|
|
26
|
+
@msg = msg
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
data/lib/rosetta_queue.rb
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
require 'activesupport' # TODO: remove dependency
|
|
2
|
-
|
|
3
1
|
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__))) unless $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__)))
|
|
4
2
|
|
|
3
|
+
require('rosetta_queue/core_ext/string') unless defined? ActiveSupport
|
|
4
|
+
require('rosetta_queue/core_ext/time') unless defined? ActiveSupport
|
|
5
|
+
|
|
5
6
|
require 'rosetta_queue/adapter'
|
|
6
7
|
require 'rosetta_queue/base'
|
|
7
8
|
require 'rosetta_queue/consumer'
|
|
@@ -18,7 +18,7 @@ module RosettaQueue
|
|
|
18
18
|
require "rosetta_queue/adapters/#{adapter_prefix}"
|
|
19
19
|
@adapter_class = RosettaQueue::Gateway.const_get("#{adapter_prefix.to_s.classify}Adapter")
|
|
20
20
|
|
|
21
|
-
rescue
|
|
21
|
+
rescue LoadError
|
|
22
22
|
raise AdapterException, "Adapter type '#{adapter_prefix}' does not match existing adapters!"
|
|
23
23
|
end
|
|
24
24
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
module RosettaQueue
|
|
2
|
+
module Gateway
|
|
3
|
+
|
|
4
|
+
module Fanout
|
|
5
|
+
def fanout_name_for(destination)
|
|
6
|
+
fanout_name = destination.gsub(/(topic|fanout)\/(.*)/, '\2')
|
|
7
|
+
raise AdapterException, "Unable to discover fanout exchange. Cannot bind queue to exchange!" unless fanout_name
|
|
8
|
+
fanout_name
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class Amqp < BaseAdapter
|
|
13
|
+
|
|
14
|
+
def initialize(adapter_settings = {})
|
|
15
|
+
raise AdapterException, "Missing adapter settings" if adapter_settings.empty?
|
|
16
|
+
@adapter_settings = adapter_settings
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def delete(destination, opts={})
|
|
20
|
+
exchange_strategy_for(destination, opts).delete(destination)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def disconnect(message_handler)
|
|
24
|
+
destination = destination_for(message_handler)
|
|
25
|
+
exchange_strategy_for(destination).unsubscribe
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def receive_once(destination, opts={})
|
|
29
|
+
exchange_strategy_for(destination, opts).receive_once(destination) do |msg|
|
|
30
|
+
return msg
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def receive_with(message_handler)
|
|
35
|
+
options = options_for(message_handler)
|
|
36
|
+
destination = destination_for(message_handler)
|
|
37
|
+
exchange_strategy_for(destination, options).receive(destination, message_handler)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def send_message(destination, message, options=nil)
|
|
41
|
+
exchange_strategy_for(destination, options).publish(destination, message)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def unsubscribe; end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
require 'eventmachine'
|
|
2
|
+
require 'mq'
|
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + "/amqp.rb")
|
|
4
|
+
|
|
5
|
+
module RosettaQueue
|
|
6
|
+
module Gateway
|
|
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
|
+
module EventedExchange
|
|
26
|
+
|
|
27
|
+
class BaseExchange
|
|
28
|
+
|
|
29
|
+
def initialize(adapter_settings, options={})
|
|
30
|
+
@adapter_settings, @options = adapter_settings, options
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def delete(destination)
|
|
34
|
+
conn.queue(destination).delete(@options)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
protected
|
|
38
|
+
|
|
39
|
+
def channel
|
|
40
|
+
@channel ||= MQ.new(conn)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def conn
|
|
44
|
+
vhost = @adapter_settings[:opts][:vhost] || "/"
|
|
45
|
+
@conn ||= AMQP.connect(:user => @adapter_settings[:user],
|
|
46
|
+
:pass => @adapter_settings[:password],
|
|
47
|
+
:host => @adapter_settings[:host],
|
|
48
|
+
:vhost => vhost)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class DirectExchange < BaseExchange
|
|
54
|
+
|
|
55
|
+
def publish(destination, message, options={})
|
|
56
|
+
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
|
+
|
|
58
|
+
queue = channel.queue(destination, options)
|
|
59
|
+
queue.publish(message, options)
|
|
60
|
+
RosettaQueue.logger.info("Publishing to #{destination} :: #{message}")
|
|
61
|
+
queue.unsubscribe
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def receive(destination, message_handler)
|
|
65
|
+
raise AdapterException, "Consumers need to run in an EventMachine 'run' block. Try wrapping them inside the evented consumer manager." unless EM.reactor_running?
|
|
66
|
+
|
|
67
|
+
queue = channel.queue(destination, @options)
|
|
68
|
+
ack = @options[:ack]
|
|
69
|
+
queue.subscribe(@options) do |header, msg|
|
|
70
|
+
RosettaQueue.logger.info("Receiving from #{destination} :: #{msg}")
|
|
71
|
+
message_handler.on_message(Filters.process_receiving(msg))
|
|
72
|
+
header.ack if ack
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def receive_once(destination, options={})
|
|
77
|
+
raise AdapterException, "Consumers need to run in an EventMachine 'run' block. (e.g., EM.run { RosettaQueue::Consumer.receive }" unless EM.reactor_running?
|
|
78
|
+
|
|
79
|
+
queue = channel.queue(destination, @options)
|
|
80
|
+
ack = @options[:ack]
|
|
81
|
+
queue.pop(@options) do |header, msg|
|
|
82
|
+
RosettaQueue.logger.info("Receiving from #{destination} :: #{msg}")
|
|
83
|
+
header.ack if ack
|
|
84
|
+
yield Filters.process_receiving(msg)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class FanoutExchange < BaseExchange
|
|
91
|
+
include Fanout
|
|
92
|
+
|
|
93
|
+
def publish(dest, msg, opts)
|
|
94
|
+
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
|
+
|
|
96
|
+
exchange = channel.fanout(fanout_name_for(dest), opts)
|
|
97
|
+
exchange.publish(msg, opts)
|
|
98
|
+
RosettaQueue.logger.info("Publishing to fanout #{dest} :: #{msg}")
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def receive(destination, message_handler)
|
|
102
|
+
raise AdapterException, "Consumers need to run in an EventMachine 'run' block. Try wrapping them inside the evented consumer manager." unless EM.reactor_running?
|
|
103
|
+
|
|
104
|
+
queue = channel.queue("queue_#{self.object_id}")
|
|
105
|
+
exchange = channel.fanout(fanout_name_for(destination), @options)
|
|
106
|
+
ack = @options[:ack]
|
|
107
|
+
|
|
108
|
+
queue.bind(exchange).subscribe(@options) do |header, msg|
|
|
109
|
+
RosettaQueue.logger.info("Receiving from #{destination} :: #{msg}")
|
|
110
|
+
message_handler.on_message(Filters.process_receiving(msg))
|
|
111
|
+
header.ack if ack
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def receive_once(destination, opts={})
|
|
116
|
+
raise AdapterException, "Consumers need to run in an EventMachine 'run' block. (e.g., EM.run { RosettaQueue::Consumer.receive }" unless EM.reactor_running?
|
|
117
|
+
|
|
118
|
+
queue = channel.queue("queue_#{self.object_id}")
|
|
119
|
+
exchange = channel.fanout(fanout_name_for(destination), opts)
|
|
120
|
+
ack = @options[:ack]
|
|
121
|
+
|
|
122
|
+
queue.bind(exchange).pop(opts) do |header, msg|
|
|
123
|
+
RosettaQueue.logger.info("Receiving from #{destination} :: #{msg}")
|
|
124
|
+
header.ack if ack
|
|
125
|
+
yield Filters.process_receiving(msg)
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
@@ -1,59 +1,29 @@
|
|
|
1
1
|
require 'bunny'
|
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + "/amqp.rb")
|
|
2
3
|
|
|
3
4
|
module RosettaQueue
|
|
4
5
|
module Gateway
|
|
5
6
|
|
|
6
7
|
# This AMQP adapter utilizes the synchronous AMPQ client 'Bunny'
|
|
7
8
|
# by celldee (http://github.com/celldee/bunny)
|
|
8
|
-
class AmqpSynchAdapter <
|
|
9
|
-
|
|
10
|
-
def initialize(adapter_settings = {})
|
|
11
|
-
raise AdapterException, "Missing adapter settings" if adapter_settings.empty?
|
|
12
|
-
@adapter_settings = adapter_settings
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def delete(destination, opts={})
|
|
16
|
-
exchange_strategy_for(destination, opts).delete(destination)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def disconnect(message_handler); end
|
|
20
|
-
|
|
21
|
-
def receive_once(destination, opts={})
|
|
22
|
-
exchange_strategy_for(destination, opts).receive_once(destination) do |msg|
|
|
23
|
-
return msg
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def receive_with(message_handler)
|
|
28
|
-
options = options_for(message_handler)
|
|
29
|
-
destination = destination_for(message_handler)
|
|
30
|
-
exchange_strategy_for(destination, options).receive(destination, message_handler)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def send_message(destination, message, options=nil)
|
|
34
|
-
exchange_strategy_for(destination, options).publish(destination, message)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def unsubscribe; end
|
|
38
|
-
|
|
9
|
+
class AmqpSynchAdapter < Amqp
|
|
39
10
|
private
|
|
40
11
|
|
|
41
|
-
def exchange_strategy_for(destination, options)
|
|
12
|
+
def exchange_strategy_for(destination, options={})
|
|
42
13
|
case destination
|
|
43
14
|
when /^fanout\./
|
|
44
|
-
@exchange ||=
|
|
15
|
+
@exchange ||= SynchExchange::FanoutExchange.new(@adapter_settings, options)
|
|
45
16
|
when /^topic\./
|
|
46
17
|
raise "Sorry. RosettaQueue can not process AMQP topics yet"
|
|
47
18
|
when /^queue\./
|
|
48
|
-
@exchange ||=
|
|
19
|
+
@exchange ||= SynchExchange::DirectExchange.new(@adapter_settings, options)
|
|
49
20
|
else
|
|
50
|
-
@exchange ||=
|
|
21
|
+
@exchange ||= SynchExchange::DirectExchange.new(@adapter_settings, options)
|
|
51
22
|
end
|
|
52
23
|
end
|
|
53
|
-
|
|
54
24
|
end
|
|
55
25
|
|
|
56
|
-
module
|
|
26
|
+
module SynchExchange
|
|
57
27
|
|
|
58
28
|
class BaseExchange
|
|
59
29
|
|
|
@@ -61,10 +31,15 @@ module RosettaQueue
|
|
|
61
31
|
@adapter_settings, @options = adapter_settings, options
|
|
62
32
|
end
|
|
63
33
|
|
|
64
|
-
def delete(destination)
|
|
65
|
-
conn.queue(destination).delete(
|
|
34
|
+
def delete(destination, options={})
|
|
35
|
+
conn.queue(destination).delete(options)
|
|
66
36
|
end
|
|
67
37
|
|
|
38
|
+
def unsubscribe
|
|
39
|
+
@queue.unsubscribe
|
|
40
|
+
conn.stop
|
|
41
|
+
end
|
|
42
|
+
|
|
68
43
|
protected
|
|
69
44
|
|
|
70
45
|
def conn
|
|
@@ -76,69 +51,73 @@ module RosettaQueue
|
|
|
76
51
|
@conn.start unless @conn.status == :connected
|
|
77
52
|
@conn
|
|
78
53
|
end
|
|
54
|
+
|
|
79
55
|
end
|
|
80
56
|
|
|
81
57
|
class DirectExchange < BaseExchange
|
|
82
58
|
|
|
83
59
|
def publish(destination, message, options={})
|
|
84
60
|
RosettaQueue.logger.info("Publishing to #{destination} :: #{message}")
|
|
85
|
-
conn.queue(destination, options)
|
|
61
|
+
queue = conn.queue(destination, options)
|
|
62
|
+
queue.publish(message, options)
|
|
63
|
+
conn.stop
|
|
86
64
|
end
|
|
87
65
|
|
|
88
66
|
def receive(destination, message_handler)
|
|
89
|
-
queue = conn.queue(destination, @options)
|
|
90
67
|
ack = @options[:ack]
|
|
91
|
-
queue.
|
|
68
|
+
@queue = conn.queue(destination, @options)
|
|
69
|
+
@queue.subscribe(@options) do |msg|
|
|
92
70
|
RosettaQueue.logger.info("Receiving from #{destination} :: #{msg}")
|
|
93
71
|
message_handler.on_message(Filters.process_receiving(msg))
|
|
94
|
-
queue.ack if ack
|
|
72
|
+
@queue.ack if ack
|
|
95
73
|
end
|
|
96
74
|
end
|
|
97
75
|
|
|
98
|
-
def receive_once(destination, options={})
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
msg =
|
|
76
|
+
def receive_once(destination, options = {})
|
|
77
|
+
ack = options[:ack]
|
|
78
|
+
@queue = conn.queue(destination, options)
|
|
79
|
+
msg = @queue.pop(options)
|
|
102
80
|
RosettaQueue.logger.info("Receiving from #{destination} :: #{msg}")
|
|
103
|
-
|
|
81
|
+
@queue.ack if ack
|
|
104
82
|
yield Filters.process_receiving(msg)
|
|
105
83
|
end
|
|
84
|
+
|
|
106
85
|
end
|
|
107
86
|
|
|
108
87
|
class FanoutExchange < BaseExchange
|
|
88
|
+
include Fanout
|
|
109
89
|
|
|
110
|
-
def fanout_name_for(destination)
|
|
111
|
-
fanout_name = destination.gsub(/fanout\/(.*)/, '\1')
|
|
112
|
-
raise "Unable to discover fanout exchange. Cannot bind queue to exchange!" unless fanout_name
|
|
113
|
-
fanout_name
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
def receive_once(destination, options={})
|
|
117
|
-
queue = conn.queue("queue_#{self.object_id}", options)
|
|
118
|
-
exchange = conn.fanout(fanout_name_for(destination), options)
|
|
119
|
-
|
|
120
|
-
msg = queue.bind(exchange).pop(@options)
|
|
121
|
-
RosettaQueue.logger.info("Receiving from #{destination} :: #{msg}")
|
|
122
|
-
yield Filters.process_receiving(msg)
|
|
123
|
-
end
|
|
124
|
-
|
|
125
90
|
def publish(destination, message, options={})
|
|
126
|
-
exchange = conn.
|
|
91
|
+
exchange = conn.exchange(fanout_name_for(destination), options.merge({:type => :fanout}))
|
|
127
92
|
exchange.publish(message, options)
|
|
128
93
|
RosettaQueue.logger.info("Publishing to fanout #{destination} :: #{message}")
|
|
129
94
|
end
|
|
130
95
|
|
|
131
96
|
def receive(destination, message_handler)
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
97
|
+
ack = @options[:ack]
|
|
98
|
+
@queue = conn.queue("queue_#{self.object_id}", @options)
|
|
99
|
+
exchange = conn.exchange(fanout_name_for(destination), @options.merge({:type => :fanout}))
|
|
100
|
+
@queue.bind(exchange)
|
|
101
|
+
@queue.subscribe(@options) do |msg|
|
|
137
102
|
RosettaQueue.logger.info("Receiving from #{destination} :: #{msg}")
|
|
138
103
|
message_handler.on_message(Filters.process_receiving(msg))
|
|
104
|
+
@queue.ack if ack
|
|
139
105
|
end
|
|
140
106
|
end
|
|
107
|
+
|
|
108
|
+
def receive_once(destination, options={})
|
|
109
|
+
ack = options[:ack]
|
|
110
|
+
@queue = conn.queue("queue_#{self.object_id}", options)
|
|
111
|
+
exchange = conn.exchange(fanout_name_for(destination), options.merge({:type => :fanout}))
|
|
112
|
+
@queue.bind(exchange)
|
|
113
|
+
msg = @queue.pop(options)
|
|
114
|
+
RosettaQueue.logger.info("Receiving from #{destination} :: #{msg}")
|
|
115
|
+
@queue.ack if ack
|
|
116
|
+
yield Filters.process_receiving(msg)
|
|
117
|
+
end
|
|
118
|
+
|
|
141
119
|
end
|
|
120
|
+
|
|
142
121
|
end
|
|
143
122
|
end
|
|
144
123
|
end
|