ruote-amqp 0.9.20 → 0.9.21
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +7 -0
- data/Manifest.txt +1 -0
- data/README.rdoc +20 -2
- data/TODO.txt +4 -0
- data/lib/ruote-amqp/listener.rb +12 -12
- data/lib/ruote-amqp/participant.rb +51 -9
- data/lib/ruote-amqp.rb +4 -5
- data/spec/listener_spec.rb +3 -3
- data/spec/participant_spec.rb +78 -3
- metadata +13 -4
data/History.txt
CHANGED
data/Manifest.txt
CHANGED
data/README.rdoc
CHANGED
@@ -23,13 +23,31 @@ Please review the detailed RDOC in RuoteAMQP::Participant and Ruote::AMQP::Liste
|
|
23
23
|
|
24
24
|
== REQUIREMENTS:
|
25
25
|
|
26
|
-
* ruote[http://openwfe.rubyforge.org] 0.9.
|
26
|
+
* ruote[http://openwfe.rubyforge.org] 0.9.21 or later
|
27
27
|
* amqp[http://github.com/tmm1/amqp] 0.6.1 or later
|
28
28
|
|
29
|
-
NOTE: It might be required that you build the amqp gem yourself
|
29
|
+
NOTE: It might be required that you build the amqp gem yourself.
|
30
|
+
|
31
|
+
ruote 0.9.21 is currently only available to build on your own since John
|
32
|
+
Mettraux is working tirelessly to ship ruote 2.0. To build your own ruote
|
33
|
+
0.9.21 gem run these commands:
|
34
|
+
|
35
|
+
$ git clone git://github.com/jmettraux/ruote.git
|
36
|
+
$ cd ruote
|
37
|
+
$ rake gem
|
38
|
+
$ sudo gem install pkg/ruote-0.9.21.gem
|
39
|
+
|
40
|
+
Please note that this requires Rubygems 1.3.2 or newer to work
|
41
|
+
|
42
|
+
If you're using ruote 0.9.20 and would like to use ruote-amqp, you can install
|
43
|
+
ruote-amqp-0.9.20, like so:
|
44
|
+
|
45
|
+
$ sudo gem install ruote-amqp -v 0.9.20
|
30
46
|
|
31
47
|
== INSTALL:
|
32
48
|
|
49
|
+
Please be sure to have read the requirements section above
|
50
|
+
|
33
51
|
* sudo gem install ruote-amqp
|
34
52
|
|
35
53
|
== DAEMON-KIT:
|
data/TODO.txt
ADDED
data/lib/ruote-amqp/listener.rb
CHANGED
@@ -6,10 +6,10 @@ module RuoteAMQP
|
|
6
6
|
#
|
7
7
|
# = AMQP Listeners
|
8
8
|
#
|
9
|
-
# Used in conjunction with the
|
9
|
+
# Used in conjunction with the RuoteAMQP::Participant, the Listener
|
10
10
|
# subscribes to a specific direct exchange and monitors for
|
11
11
|
# incoming workitems. It expects workitems to arrive serialized as
|
12
|
-
# JSON
|
12
|
+
# JSON.
|
13
13
|
#
|
14
14
|
# == Configuration
|
15
15
|
#
|
@@ -27,12 +27,12 @@ module RuoteAMQP
|
|
27
27
|
#
|
28
28
|
# Register the listener with the engine:
|
29
29
|
#
|
30
|
-
# engine.register_listener(
|
30
|
+
# engine.register_listener( RuoteAMQP::Listener )
|
31
31
|
#
|
32
32
|
# The listener leverages the asynchronous nature of the amqp gem,
|
33
33
|
# so no timers are setup when initialized.
|
34
34
|
#
|
35
|
-
# See the
|
35
|
+
# See the RuoteAMQP::Participant docs for information on sending
|
36
36
|
# workitems out to remote participants, and have them send replies
|
37
37
|
# to the correct direct exchange specified in the workitem
|
38
38
|
# attributes.
|
@@ -40,13 +40,13 @@ module RuoteAMQP
|
|
40
40
|
class Listener < OpenWFE::Service
|
41
41
|
include OpenWFE::WorkItemListener
|
42
42
|
|
43
|
-
# Listening queue
|
44
|
-
@@queue = 'ruote'
|
45
|
-
|
46
43
|
class << self
|
47
44
|
|
45
|
+
# Listening queue
|
46
|
+
attr_writer :queue
|
47
|
+
|
48
48
|
def queue
|
49
|
-
|
49
|
+
@queue ||= 'ruote'
|
50
50
|
end
|
51
51
|
|
52
52
|
end
|
@@ -56,7 +56,7 @@ module RuoteAMQP
|
|
56
56
|
def initialize( service_name, options )
|
57
57
|
|
58
58
|
if q = options.delete(:queue)
|
59
|
-
|
59
|
+
self.class.queue = q
|
60
60
|
end
|
61
61
|
|
62
62
|
super( service_name, options )
|
@@ -65,9 +65,9 @@ module RuoteAMQP
|
|
65
65
|
@em_thread = Thread.new { EM.run } unless EM.reactor_running?
|
66
66
|
#end
|
67
67
|
|
68
|
-
MQ.queue(
|
68
|
+
MQ.queue( self.class.queue, :durable => true ).subscribe do |message|
|
69
69
|
workitem = decode_workitem( message )
|
70
|
-
ldebug { "workitem from '#{
|
70
|
+
ldebug { "workitem from '#{self.class.queue}': #{workitem.inspect}" }
|
71
71
|
handle_item( workitem )
|
72
72
|
end
|
73
73
|
end
|
@@ -85,7 +85,7 @@ module RuoteAMQP
|
|
85
85
|
def decode_workitem( msg )
|
86
86
|
ldebug { "decoding workitem from: #{msg}" }
|
87
87
|
|
88
|
-
hash =
|
88
|
+
hash = OpenWFE::Json.decode(msg)
|
89
89
|
OpenWFE.workitem_from_h( hash )
|
90
90
|
end
|
91
91
|
end
|
@@ -2,9 +2,9 @@ module RuoteAMQP
|
|
2
2
|
|
3
3
|
# = AMQP Participants
|
4
4
|
#
|
5
|
-
# The
|
5
|
+
# The RuoteAMQP::Participant allows you to send workitems (serialized as
|
6
6
|
# JSON) or messages to any AMQP queues right from the process
|
7
|
-
# definition. When combined with the
|
7
|
+
# definition. When combined with the RuoteAMQP::Listener you can easily
|
8
8
|
# leverage an extremely powerful local/remote participant
|
9
9
|
# combinations.
|
10
10
|
#
|
@@ -30,12 +30,12 @@ module RuoteAMQP
|
|
30
30
|
# Setting up the participant
|
31
31
|
#
|
32
32
|
# engine.register_participant(
|
33
|
-
# :amqp,
|
33
|
+
# :amqp, RuoteAMQP::Participant )
|
34
34
|
#
|
35
35
|
# Setup a participant that always replies to the engine
|
36
36
|
#
|
37
37
|
# engine.register_participant(
|
38
|
-
# :
|
38
|
+
# :amqp, RuoteAMQP::Participant.new(:reply_by_default => true ) )
|
39
39
|
#
|
40
40
|
# Sending a message example
|
41
41
|
#
|
@@ -63,13 +63,41 @@ module RuoteAMQP
|
|
63
63
|
#
|
64
64
|
# When waiting for a reply it only makes sense to send a workitem.
|
65
65
|
#
|
66
|
+
# Keeping things DRY with participant name to queue maps:
|
67
|
+
#
|
68
|
+
# amqp = RuoteAMQP::Participant.new( :default_queue => 'test' )
|
69
|
+
# amqp.map_participant 'george', 'whitehouse'
|
70
|
+
# amqp.map_participant 'barak', 'whitehouse'
|
71
|
+
# amqp.map_participant 'greenspan', 'treasury'
|
72
|
+
#
|
73
|
+
# engine.register_participant( :george, amqp )
|
74
|
+
# engine.register_participant( :barak, amqp )
|
75
|
+
# engine.register_participant( :greespan, amqp )
|
76
|
+
# engine.register_participant( :amqp, amqp )
|
77
|
+
#
|
78
|
+
# class DryAmqProcess0 < OpenWFE::ProcessDefinition
|
79
|
+
# cursor :break_if => "${f:economy_recovered}" do
|
80
|
+
# # Workitem sent to 'whitehouse' queue
|
81
|
+
# george :activity => 'Tank economy'
|
82
|
+
#
|
83
|
+
# # Workitem sent to 'treasury' queue
|
84
|
+
# greenspan :activity => 'Resign'
|
85
|
+
#
|
86
|
+
# # Workitem sent to 'whitehouse' queue
|
87
|
+
# barak :activity => 'Cleanup mess'
|
88
|
+
#
|
89
|
+
# # Workitem sent to default 'test' queue
|
90
|
+
# amqp :activity => 'Notify CNN'
|
91
|
+
# end
|
92
|
+
# end
|
93
|
+
#
|
66
94
|
# == Workitem modifications
|
67
95
|
#
|
68
96
|
# To ease replies, and additional workitem attribute is set:
|
69
97
|
#
|
70
98
|
# 'reply_queue'
|
71
99
|
#
|
72
|
-
# +reply_queue+ has the name of the queue where the
|
100
|
+
# +reply_queue+ has the name of the queue where the RuoteAMQP::Listener
|
73
101
|
# expects replies from remote participants
|
74
102
|
#
|
75
103
|
# == AMQP notes
|
@@ -87,12 +115,20 @@ module RuoteAMQP
|
|
87
115
|
# Accepts an options hash with the following keys:
|
88
116
|
#
|
89
117
|
# * :reply_by_default => (bool) false by default
|
118
|
+
# * :default_queue => (string) nil by default
|
90
119
|
def initialize( options = {} )
|
91
120
|
ensure_reactor!
|
92
121
|
|
93
122
|
@options = {
|
94
|
-
:reply_by_default => false
|
123
|
+
:reply_by_default => false,
|
124
|
+
:default_queue => nil
|
95
125
|
}.merge( options )
|
126
|
+
|
127
|
+
@participant_maps = {}
|
128
|
+
end
|
129
|
+
|
130
|
+
def map_participant( name, queue )
|
131
|
+
@participant_maps[ name ] = queue
|
96
132
|
end
|
97
133
|
|
98
134
|
# Process the workitem at hand. By default the workitem will be
|
@@ -106,7 +142,7 @@ module RuoteAMQP
|
|
106
142
|
ldebug { "consuming workitem" }
|
107
143
|
ensure_reactor!
|
108
144
|
|
109
|
-
if target_queue = workitem
|
145
|
+
if target_queue = determine_queue( workitem )
|
110
146
|
|
111
147
|
q = MQ.queue( target_queue, :durable => true )
|
112
148
|
|
@@ -138,12 +174,18 @@ module RuoteAMQP
|
|
138
174
|
@em_thread.join if @em_thread
|
139
175
|
end
|
140
176
|
|
141
|
-
|
177
|
+
private
|
178
|
+
|
179
|
+
def determine_queue( workitem )
|
180
|
+
workitem.params['queue'] ||
|
181
|
+
@participant_maps[ workitem.participant_name ] ||
|
182
|
+
@options[:default_queue]
|
183
|
+
end
|
142
184
|
|
143
185
|
# Encode (and extend) the workitem as JSON
|
144
186
|
def encode_workitem( wi )
|
145
187
|
wi.attributes['reply_queue'] = Listener.queue
|
146
|
-
|
188
|
+
OpenWFE::Json.encode( wi.to_h )
|
147
189
|
end
|
148
190
|
|
149
191
|
def ensure_reactor!
|
data/lib/ruote-amqp.rb
CHANGED
@@ -5,21 +5,20 @@ begin
|
|
5
5
|
require 'openwfe'
|
6
6
|
rescue LoadError
|
7
7
|
require 'rubygems'
|
8
|
-
gem 'ruote', '>= 0.9.
|
8
|
+
gem 'ruote', '>= 0.9.21'
|
9
9
|
require 'openwfe'
|
10
10
|
end
|
11
11
|
require 'openwfe/version'
|
12
12
|
|
13
|
-
if OpenWFE::OPENWFERU_VERSION < '0.9.
|
14
|
-
raise "ruote-amqp requires at least ruote-0.9.
|
13
|
+
if OpenWFE::OPENWFERU_VERSION < '0.9.21'
|
14
|
+
raise "ruote-amqp requires at least ruote-0.9.21"
|
15
15
|
end
|
16
16
|
|
17
17
|
require 'yaml'
|
18
|
-
require 'json'
|
19
18
|
require 'mq'
|
20
19
|
|
21
20
|
module RuoteAMQP
|
22
|
-
VERSION = '0.9.
|
21
|
+
VERSION = '0.9.21'
|
23
22
|
|
24
23
|
autoload 'Participant', 'ruote-amqp/participant'
|
25
24
|
autoload 'Listener', 'ruote-amqp/listener'
|
data/spec/listener_spec.rb
CHANGED
@@ -29,17 +29,17 @@ describe RuoteAMQP::Listener do
|
|
29
29
|
|
30
30
|
loop do
|
31
31
|
break unless @msg.nil?
|
32
|
-
sleep 1
|
32
|
+
sleep 0.1
|
33
33
|
end
|
34
34
|
end
|
35
35
|
rescue Timeout::Error
|
36
36
|
violated "Timeout waiting for message"
|
37
37
|
end
|
38
38
|
|
39
|
-
wi = OpenWFE::InFlowWorkItem.from_h(
|
39
|
+
wi = OpenWFE::InFlowWorkItem.from_h( OpenWFE::Json.decode( @msg ) )
|
40
40
|
wi.attributes['foo'] = "bar"
|
41
41
|
|
42
|
-
MQ.queue( wi.attributes['reply_queue'] ).publish(
|
42
|
+
MQ.queue( wi.attributes['reply_queue'] ).publish( OpenWFE::Json.encode( wi.to_h ) )
|
43
43
|
|
44
44
|
wait( fei )
|
45
45
|
|
data/spec/participant_spec.rb
CHANGED
@@ -27,7 +27,7 @@ describe RuoteAMQP::Participant, :type => :ruote do
|
|
27
27
|
|
28
28
|
loop do
|
29
29
|
break unless @msg.nil?
|
30
|
-
sleep 1
|
30
|
+
sleep 0.1
|
31
31
|
end
|
32
32
|
end
|
33
33
|
rescue Timeout::Error
|
@@ -62,7 +62,7 @@ describe RuoteAMQP::Participant, :type => :ruote do
|
|
62
62
|
|
63
63
|
loop do
|
64
64
|
break unless @msg.nil?
|
65
|
-
sleep 1
|
65
|
+
sleep 0.1
|
66
66
|
end
|
67
67
|
end
|
68
68
|
rescue Timeout::Error
|
@@ -96,7 +96,7 @@ describe RuoteAMQP::Participant, :type => :ruote do
|
|
96
96
|
|
97
97
|
loop do
|
98
98
|
break unless @msg.nil?
|
99
|
-
sleep 1
|
99
|
+
sleep 0.1
|
100
100
|
end
|
101
101
|
end
|
102
102
|
rescue Timeout::Error
|
@@ -105,4 +105,79 @@ describe RuoteAMQP::Participant, :type => :ruote do
|
|
105
105
|
|
106
106
|
@msg.should == 'foo'
|
107
107
|
end
|
108
|
+
|
109
|
+
it "should support a default queue name" do
|
110
|
+
|
111
|
+
pdef = <<-EOF
|
112
|
+
class AmqpParticipant0 < OpenWFE::ProcessDefinition
|
113
|
+
|
114
|
+
sequence do
|
115
|
+
amqp 'reply_anyway' => true
|
116
|
+
echo 'done.'
|
117
|
+
end
|
118
|
+
end
|
119
|
+
EOF
|
120
|
+
|
121
|
+
amqp = RuoteAMQP::Participant.new( :default_queue => 'test5' )
|
122
|
+
@engine.register_participant( :amqp, amqp )
|
123
|
+
|
124
|
+
run_definition( pdef )
|
125
|
+
|
126
|
+
@tracer.to_s.should == 'done.'
|
127
|
+
|
128
|
+
begin
|
129
|
+
Timeout::timeout(10) do
|
130
|
+
@msg = nil
|
131
|
+
MQ.queue('test5').subscribe { |msg| @msg = msg }
|
132
|
+
|
133
|
+
loop do
|
134
|
+
break unless @msg.nil?
|
135
|
+
sleep 0.1
|
136
|
+
end
|
137
|
+
end
|
138
|
+
rescue Timeout::Error
|
139
|
+
violated "Timeout waiting for message"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should support mapping participant names to queue names" do
|
144
|
+
pdef = <<-EOF
|
145
|
+
class AmqpParticipant0 < OpenWFE::ProcessDefinition
|
146
|
+
|
147
|
+
sequence do
|
148
|
+
q1
|
149
|
+
q2
|
150
|
+
amqp
|
151
|
+
echo 'done.'
|
152
|
+
end
|
153
|
+
end
|
154
|
+
EOF
|
155
|
+
|
156
|
+
amqp = RuoteAMQP::Participant.new( :reply_by_default => true, :default_queue => 'test6' )
|
157
|
+
amqp.map_participant( 'q1', 'test7' )
|
158
|
+
amqp.map_participant( 'q2', 'test8' )
|
159
|
+
@engine.register_participant( :amqp, amqp )
|
160
|
+
@engine.register_participant( :q1, amqp )
|
161
|
+
@engine.register_participant( :q2, amqp )
|
162
|
+
|
163
|
+
run_definition( pdef )
|
164
|
+
|
165
|
+
@tracer.to_s.should == 'done.'
|
166
|
+
|
167
|
+
[ 'test6', 'test7', 'test8' ].each do |q|
|
168
|
+
begin
|
169
|
+
Timeout::timeout(10) do
|
170
|
+
@msg = nil
|
171
|
+
MQ.queue( q ).subscribe { |msg| @msg = msg }
|
172
|
+
|
173
|
+
loop do
|
174
|
+
break unless @msg.nil?
|
175
|
+
sleep 0.1
|
176
|
+
end
|
177
|
+
end
|
178
|
+
rescue Timeout::Error
|
179
|
+
violated "Timeout waiting for message on #{q}"
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
108
183
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruote-amqp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.21
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kenneth Kalmer
|
@@ -42,7 +42,12 @@ dependencies:
|
|
42
42
|
- !ruby/object:Gem::Version
|
43
43
|
version: 2.3.2
|
44
44
|
version:
|
45
|
-
description:
|
45
|
+
description: |-
|
46
|
+
ruote-amqp provides an AMQP participant/listener pair that allows you to
|
47
|
+
distribute workitems out to AMQP consumers for processing.
|
48
|
+
|
49
|
+
To learn more about remote participants in ruote please see
|
50
|
+
http://openwfe.rubyforge.org/part.html
|
46
51
|
email:
|
47
52
|
- kenneth.kalmer@gmail.com
|
48
53
|
executables: []
|
@@ -53,12 +58,14 @@ extra_rdoc_files:
|
|
53
58
|
- History.txt
|
54
59
|
- Manifest.txt
|
55
60
|
- PostInstall.txt
|
61
|
+
- TODO.txt
|
56
62
|
files:
|
57
63
|
- History.txt
|
58
64
|
- Manifest.txt
|
59
65
|
- PostInstall.txt
|
60
66
|
- README.rdoc
|
61
67
|
- Rakefile
|
68
|
+
- TODO.txt
|
62
69
|
- lib/ruote-amqp.rb
|
63
70
|
- lib/ruote-amqp/listener.rb
|
64
71
|
- lib/ruote-amqp/participant.rb
|
@@ -76,6 +83,8 @@ files:
|
|
76
83
|
- tasks/rspec.rake
|
77
84
|
has_rdoc: true
|
78
85
|
homepage: http://github.com/kennethkalmer/ruote-amqp
|
86
|
+
licenses: []
|
87
|
+
|
79
88
|
post_install_message: PostInstall.txt
|
80
89
|
rdoc_options:
|
81
90
|
- --main
|
@@ -97,9 +106,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
97
106
|
requirements: []
|
98
107
|
|
99
108
|
rubyforge_project: ruote-amqp
|
100
|
-
rubygems_version: 1.3.
|
109
|
+
rubygems_version: 1.3.4
|
101
110
|
signing_key:
|
102
|
-
specification_version:
|
111
|
+
specification_version: 3
|
103
112
|
summary: ruote-amqp provides an AMQP participant/listener pair that allows you to distribute workitems out to AMQP consumers for processing
|
104
113
|
test_files: []
|
105
114
|
|