ruote-amqp 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,350 @@
1
+ #--
2
+ # Copyright (c) 2010-2012, Kenneth Kalmer, John Mettraux.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #++
22
+
23
+
24
+ module Ruote::Amqp
25
+
26
+ #
27
+ # This participant publishes messages on AMQP exchanges.
28
+ #
29
+ # == options
30
+ #
31
+ # A few options are supported. They can be declared at 3 levels:
32
+ #
33
+ # * options (when the participant is registered)
34
+ #
35
+ # dashboard.register(
36
+ # 'amqp_participant',
37
+ # Ruote::Amqp::Participant,
38
+ # :routing_key => 'nada.x')
39
+ #
40
+ # * params (from the process definition)
41
+ #
42
+ # sequence do
43
+ # amqp_participant :routing_key => 'nada.x'
44
+ # end
45
+ #
46
+ # * fields (from the passing workitem)
47
+ #
48
+ # sequence do
49
+ # set 'f:routing_key' => 'nada.x'
50
+ # amqp_participant
51
+ # end
52
+ #
53
+ # The 'conf' option (only available at participant registration) decides
54
+ # which levels are enabled or not.
55
+ #
56
+ # By default 'conf' is set to 'params, fields, options'.
57
+ #
58
+ # === 'conf'
59
+ #
60
+ # As said above, this option decides who can tweak this participant's
61
+ # options. It accepts a comma-separated list of levels.
62
+ #
63
+ # The levels are "params", "fields", "options".
64
+ #
65
+ # The order in which the levels are given is the order in which they
66
+ # are investigated for values.
67
+ #
68
+ # === 'connection'
69
+ #
70
+ # A hash of connection options. This is direcly fed to the amqp gem, the
71
+ # options of that gem apply thus ('host', 'port', 'vhost', 'username' and
72
+ # 'password').
73
+ #
74
+ # If no 'connection' (or :connection) hash is passed, the participant
75
+ # will attempt to use the connection (AMQP::Session) found in
76
+ # Ruote::Amqp.session. If there is nothing in there, it will [attempt] to
77
+ # create a new connection with AMQP's default settings.
78
+ #
79
+ # === 'exchange'
80
+ #
81
+ # Accepts a two or three sized Array.
82
+ #
83
+ # The first element is a string or symbol detailing the exchange type,
84
+ # like :direct, :fanout, :topic, ...
85
+ #
86
+ # The second element is an exchange name.
87
+ #
88
+ # The third, optional, element is a hash of exchange options.
89
+ #
90
+ # There is more information at http://rubyamqp.info/
91
+ #
92
+ # By default, 'exchange' is set to [ 'direct', '' ] (the default exchange).
93
+ #
94
+ # Note: you cannot pass an instantiated Ruby-AMQP exchange here. Ruote
95
+ # cannot serialize it for remote workers, so the settings are passed
96
+ # in a flat form, easily JSONifiable.
97
+ #
98
+ # === 'field_prefix'
99
+ #
100
+ # Sometimes one wants to separate his AMQP participant settings from other
101
+ # workitem fields.
102
+ #
103
+ # dashboard.register(
104
+ # 'amqp_participant',
105
+ # Ruote::Amqp::Participant,
106
+ # :conf => 'fields', :field_prefix => 'amqp_')
107
+ #
108
+ # registers a participant that draws is configuration from workitem fields
109
+ # prefixed with 'amqp_'.
110
+ #
111
+ # Note that setting this option doesn't implicitely add 'fields' to the
112
+ # 'conf' option.
113
+ #
114
+ # === 'forget'
115
+ #
116
+ # When set to true forces the participant to reply to the engine immediately
117
+ # after the message got published, in a "fire and forget" fashion.
118
+ #
119
+ # === 'routing_key'
120
+ #
121
+ # Depending on the exchange used, this option lets you influence how the
122
+ # exchange routes the message towards queues.
123
+ #
124
+ # Consult your AMQP documentation for more information.
125
+ #
126
+ # === 'message'
127
+ #
128
+ # By default, the workitem is turned into a JSON string and transmitted in
129
+ # the AMQP message payload. If this 'message' option is set, its value is
130
+ # used as the payload.
131
+ #
132
+ # === 'persistent'
133
+ #
134
+ # If this option is set to something else than false or nil, messages
135
+ # messages published by this participant will be persistent (hopefully
136
+ # the queues they'll end up in will be persistent as well).
137
+ #
138
+ #
139
+ # == #encode_workitem
140
+ #
141
+ # The default way to encode a workitem before pushing it to the exchange
142
+ # is by turning it entirely into a JSON string.
143
+ #
144
+ # To alter this, one can subclass this participant and provide its own
145
+ # #encode_workitem(wi) method:
146
+ #
147
+ # require 'yaml'
148
+ #
149
+ # class MyAmqpParticipant < Ruote::Amqp::Participant
150
+ #
151
+ # def encode_workitem(workitem)
152
+ # YAML.dump(workitem)
153
+ # end
154
+ # end
155
+ #
156
+ # or when one needs to filter some fields:
157
+ #
158
+ # class MyAmqpParticipant < Ruote::Amqp::Participant
159
+ #
160
+ # def encode_workitem(workitem)
161
+ # workitem.fields.delete_if { |k, v| k.match(/^private_/) }
162
+ # super(workitem)
163
+ # end
164
+ # end
165
+ #
166
+ class Participant
167
+ include Ruote::LocalParticipant
168
+
169
+ # Initializing the participant, right before calling #on_workitem or
170
+ # another on_ method.
171
+ #
172
+ def initialize(options)
173
+
174
+ @options = options
175
+
176
+ @conf = (@options['conf'] || 'params, fields, options').split(/\s*,\s*/)
177
+ @conf = %w[ params fields options ] if @conf.include?('all')
178
+
179
+ @field_prefix = @options['field_prefix'] || ''
180
+ end
181
+
182
+ # Workitem consumption code.
183
+ #
184
+ def on_workitem
185
+
186
+ instantiate_exchange.publish(
187
+ message,
188
+ :routing_key => routing_key,
189
+ :persistent => persistent,
190
+ :correlation_id => correlation_id)
191
+
192
+ reply if forget
193
+ end
194
+
195
+ def on_cancel
196
+
197
+ return if opt('discard_cancel')
198
+
199
+ instantiate_exchange.publish(
200
+ encode_cancelitem,
201
+ :routing_key => routing_key,
202
+ :persistent => persistent,
203
+ :correlation_id => correlation_id)
204
+ end
205
+
206
+ # No need for a dedicated thread when dispatching messages. Respond
207
+ # true.
208
+ #
209
+ def do_not_thread; true; end
210
+
211
+ # Returns the exchange coordinates (a triple [ type, name, options ]).
212
+ # Defaults to the direct exchange.
213
+ #
214
+ # Available as a method so it can be overriden (the return value could
215
+ # depend on the @workitem or other factors).
216
+ #
217
+ def exchange
218
+
219
+ opt('exchange') || [ 'direct', '', {} ]
220
+ #
221
+ # defaults to the "default exchange"...
222
+ end
223
+
224
+ # Returns the message to publish.
225
+ #
226
+ # Available as a method so it can be overriden (the return value could
227
+ # depend on the @workitem or other factors).
228
+ #
229
+ def message; opt('message') || encode_workitem; end
230
+
231
+ # Returns the routing key for the message to publish.
232
+ #
233
+ # Available as a method so it can be overriden (the return value could
234
+ # depend on the @workitem or other factors).
235
+ #
236
+ def routing_key; opt('routing_key'); end
237
+
238
+ # Returns whether the publish should be persistent or not.
239
+ #
240
+ # Available as a method so it can be overriden (the return value could
241
+ # depend on the @workitem or other factors).
242
+ #
243
+ def persistent; opt('persistent'); end
244
+
245
+ # Returns the correlation_id for the message publication. Returns ''
246
+ # by default.
247
+ #
248
+ # Available as a method so it can be overriden (the return value could
249
+ # depend on the @workitem or other factors).
250
+ #
251
+ def correlation_id
252
+
253
+ opt('correlation_id') || ''
254
+ end
255
+
256
+ # Returns something true-ish if the participant should not reply to the
257
+ # engine once the publish operation is done.
258
+ #
259
+ # Available as a method so it can be overriden (the return value could
260
+ # depend on the @workitem or other factors).
261
+ #
262
+ def forget; opt('forget'); end
263
+
264
+ protected
265
+
266
+ # How a workitem is turned into an AMQP message payload (string).
267
+ #
268
+ # Feel free to override this method to accommodate your needs.
269
+ #
270
+ def encode_workitem
271
+
272
+ workitem.as_json
273
+ end
274
+
275
+ # How a "cancelitem" is turned into an AMQP message payload (string).
276
+ #
277
+ # Feel free to override this method to accommodate your needs.
278
+ #
279
+ def encode_cancelitem
280
+
281
+ Rufus::Json.encode(
282
+ 'cancel' => true, 'fei' => @fei.h, 'flavour' => @flavour)
283
+ end
284
+
285
+ # Default AMQP.connect method.
286
+ #
287
+ # Feel free to override this method to accommodate your needs (See
288
+ # the README for an example).
289
+ #
290
+ def amqp_connect
291
+
292
+ ocon = opt('connection')
293
+
294
+ if Ruote::Amqp.session && ( ! ocon)
295
+ Ruote::Amqp.session
296
+ else
297
+ AMQP.connect(Ruote.keys_to_sym(ocon || {}))
298
+ end
299
+ end
300
+
301
+ # Given connection options passed at registration time (when the
302
+ # participant is registered in ruote) or from the process definition,
303
+ # returns an AMQP::Channel instance.
304
+ #
305
+ def channel
306
+
307
+ Thread.current['_ruote_amqp_channel'] ||= AMQP::Channel.new(amqp_connect)
308
+ end
309
+
310
+ # Given exchange options passed at registrations time or from the process
311
+ # definition, returns an AMQP::Exchange instance.
312
+ #
313
+ def instantiate_exchange
314
+
315
+ Thread.current['_ruote_amqp_exchange'] ||= begin
316
+
317
+ exc = exchange
318
+ type, name, options = exc
319
+
320
+ raise ArgumentError.new(
321
+ "couldn't determine exchange from #{exc.inspect}"
322
+ ) unless name
323
+
324
+ exchange_opts = (options || {}).each_with_object({}) { |(k, v), h|
325
+ h[k.to_sym] = v
326
+ }
327
+
328
+ AMQP::Exchange.new(channel, type.to_sym, name, exchange_opts)
329
+ end
330
+ end
331
+
332
+ # The mechanism for looking up options like 'connection', 'exchange',
333
+ # 'routing_key' in either the participant options, the process
334
+ # definition or the workitem fields...
335
+ #
336
+ def opt(key)
337
+
338
+ @conf.each do |type|
339
+
340
+ container = (type == 'options' ? @options : workitem.send(type))
341
+ k = type == 'fields' ? "#{@field_prefix}#{key}" : key
342
+
343
+ return container[k] if container.has_key?(k)
344
+ end
345
+
346
+ nil
347
+ end
348
+ end
349
+ end
350
+
@@ -0,0 +1,181 @@
1
+ #--
2
+ # Copyright (c) 2010-2012, Kenneth Kalmer, John Mettraux.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #++
22
+
23
+
24
+ module Ruote::Amqp
25
+
26
+ #
27
+ # A receiver is plugged between a ruote engine/storage and an AMQP queue.
28
+ # It will listen on the queue for messages, try to turn them into
29
+ # workitems and feed those workitem back to the engine/storage (in the usual
30
+ # use case, those workitems were initially emitted by the engine).
31
+ #
32
+ # == #decode_message(headers, payload)
33
+ #
34
+ # By default, the receiver expects the incoming workitem to be serialized
35
+ # entirely in the payload of the AMQP message. One can change this
36
+ # behaviour by overriding the #decode_workitem method (usually when
37
+ # subclassing)
38
+ #
39
+ # class MyYamlReceiver < Ruote::Amqp::Receiver
40
+ # def decode_message(headers, payload)
41
+ # YAML.load(payload)
42
+ # end
43
+ # end
44
+ #
45
+ # #decode_message is supposed to return a Ruby hash (describing either a
46
+ # workitem or a launchitem), the difference is explained below.
47
+ #
48
+ # === workitems and launchitems
49
+ #
50
+ # The standard use case is to accept workitems coming back (they probably
51
+ # left the engine via Ruote::Amqp::Participant). But it's also OK
52
+ # to accept "launchitems", hashes with at least one 'process_definition'
53
+ # (or 'definition') entry.
54
+ #
55
+ # Upon receiving a launchitem, the receiver will launch a new process
56
+ # instances.
57
+ #
58
+ # Launchitems may have two more optional entries, 'workitems_fields' (or
59
+ # 'fields') and 'process_variables' (or 'variables').
60
+ #
61
+ # 'workitem_fields' must contain a hash of initial workitem fields (they will
62
+ # populate the initial workitem.
63
+ #
64
+ # 'process_variables' are a very advanced option. It's possible to set the
65
+ # initial variables in a workflow. Read the general ruote documentation to
66
+ # learn about the difference between fields and variables.
67
+ #
68
+ # The #decode_message is supposed to return a hash representing either a
69
+ # workitem, either a launchitem.
70
+ #
71
+ # == #handle_error(err)
72
+ #
73
+ # Out of the box, the receiver will print out to $stderr the details of
74
+ # errors it encounters when receiving, decoding and handing back the
75
+ # workitems (messages?) to the engine. This can be changed by overriding
76
+ # the #handle_error method:
77
+ #
78
+ # class MyReceiver < Ruote::Amqp::Receiver
79
+ # def handle_error(err)
80
+ # ThatLoggerService.log(err)
81
+ # end
82
+ # end
83
+ #
84
+ #
85
+ # == initialization options
86
+ #
87
+ # One can set the "launch_only" option to true when initializing the receiver
88
+ # to prevent it from handling anything but launchitems.
89
+ #
90
+ # receiver = Ruote::Amqp::Receiver.new(
91
+ # @dashboard, @amqp_queue, :launch_only => true)
92
+ #
93
+ # 'launch_only' (string) is valid too.
94
+ #
95
+ class Receiver < Ruote::Receiver
96
+
97
+ attr_reader :queue
98
+
99
+ def initialize(engine_or_storage, queue, options={})
100
+
101
+ super(engine_or_storage, Ruote.keys_to_s(options))
102
+
103
+ @queue = queue
104
+ @queue.subscribe(&method(:handle))
105
+ end
106
+
107
+ def shutdown
108
+
109
+ @queue.unsubscribe
110
+ end
111
+
112
+ protected
113
+
114
+ def handle(header, payload)
115
+
116
+ item = decode_message(header, payload)
117
+
118
+ if item['error'] && item['fei']
119
+ flunk(item)
120
+ elsif item['fields'] && item['fei']
121
+ receive(item)
122
+ elsif item['process_definition'] || item['definition']
123
+ launch(item)
124
+ else
125
+ raise ArgumentError.new("cannot receive or launch #{item.inspect}")
126
+ end
127
+
128
+ rescue => e
129
+ handle_error(e)
130
+ end
131
+
132
+ def decode_message(header, payload)
133
+
134
+ Rufus::Json.decode(payload)
135
+ end
136
+
137
+ def handle_error(err)
138
+
139
+ $stderr.puts '**err**'
140
+ $stderr.puts err.inspect
141
+ $stderr.puts err.backtrace
142
+ end
143
+
144
+ def flunk(h)
145
+
146
+ return if @options['launch_only']
147
+
148
+ err = h.delete('error')
149
+
150
+ args = case err
151
+ when String then [ RemoteError, err ]
152
+ when Hash then [ Ruote.constantize(err['class']), err['message'] ]
153
+ else [ RemoteError, err.inspect ]
154
+ end
155
+
156
+ super(h, *args)
157
+ end
158
+
159
+ def receive(h)
160
+
161
+ return if @options['launch_only']
162
+
163
+ super(h)
164
+ end
165
+
166
+ def launch(h)
167
+
168
+ super(
169
+ h['process_definition'] || h['definition'],
170
+ h['workitem_fields'] || h['fields'] || {},
171
+ h['process_variables'] || h['variables'] || {})
172
+ end
173
+ end
174
+
175
+ #
176
+ # Used to wrap errors that come as string (well, errors that don't come
177
+ # with a class name). Could be thought of as "anonymous remote error".
178
+ #
179
+ class RemoteError < StandardError; end
180
+ end
181
+
@@ -0,0 +1,28 @@
1
+ #--
2
+ # Copyright (c) 2010-2012, Kenneth Kalmer, John Mettraux.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #++
22
+
23
+
24
+ module Ruote::Amqp
25
+
26
+ VERSION = '2.3.0'
27
+ end
28
+
data/lib/ruote/amqp.rb ADDED
@@ -0,0 +1,68 @@
1
+ #--
2
+ # Copyright (c) 2010-2012, Kenneth Kalmer, John Mettraux.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #++
22
+
23
+ require 'amqp'
24
+ require 'ruote'
25
+
26
+ require 'ruote/amqp/participant'
27
+ require 'ruote/amqp/alert_participant'
28
+ require 'ruote/amqp/receiver'
29
+
30
+
31
+ module Ruote::Amqp
32
+
33
+ # Returns the AMQP::Session shared by the ruote participants (and potentially
34
+ # the receivers too).
35
+ #
36
+ # Returns nil if none is set (the participant will mostly create a connection
37
+ # on their own).
38
+ #
39
+ # See http://rubydoc.info/github/ruby-amqp/amqp/master/AMQP/Session
40
+ #
41
+ def self.session
42
+
43
+ @session
44
+ end
45
+
46
+ # Sets the AMQP::Session shared by the ruote participants (and potentially
47
+ # the receivers too).
48
+ #
49
+ # Ruote::Amqp.session = AMQP.connect(:auto_recovery => true) do |con|
50
+ # con.on_recovery do |con|
51
+ # puts "Recovered..."
52
+ # end
53
+ # connection.on_tcp_connection_loss do |con, settings|
54
+ # puts "Reconnecting... please wait"
55
+ # conn.reconnect(false, 20)
56
+ # end
57
+ # end
58
+ #
59
+ # (Thanks Jim Li - https://github.com/marsbomber/ruote-amqp/commit/0f36a41f)
60
+ #
61
+ # See http://rubydoc.info/github/ruby-amqp/amqp/master/AMQP/Session
62
+ #
63
+ def self.session=(s)
64
+
65
+ @session = s
66
+ end
67
+ end
68
+
data/lib/ruote-amqp.rb CHANGED
@@ -1,80 +1,3 @@
1
1
 
2
- require 'mq'
3
-
4
- require 'ruote-amqp/version'
5
-
6
-
7
- #
8
- # AMQP participant and listener pair for ruote.
9
- #
10
- # == Documentation
11
- #
12
- # See #RuoteAMQP::Listener and #RuoteAMQP::Participant for detailed
13
- # documentation on using each of them.
14
- #
15
- # == AMQP Notes
16
- #
17
- # RuoteAMQP uses durable queues and persistent messages by default, to ensure
18
- # no messages get lost along the way and that running expressions doesn't have
19
- # to be restarted in order for messages to be resent.
20
- #
21
- module RuoteAMQP
22
-
23
- autoload 'ParticipantProxy', 'ruote-amqp/participant'
24
-
25
- autoload 'Receiver', 'ruote-amqp/receiver'
26
- autoload 'WorkitemListener', 'ruote-amqp/workitem_listener'
27
- autoload 'LaunchitemListener', 'ruote-amqp/launchitem_listener'
28
-
29
- class << self
30
-
31
- attr_writer :use_persistent_messages
32
-
33
- # Whether or not to use persistent messages (true by default)
34
- def use_persistent_messages?
35
- @use_persistent_messages = true if @use_persistent_messages.nil?
36
- @use_persistent_messages
37
- end
38
-
39
- # Ensure the AMQP connection is started
40
- def start!
41
- return if started?
42
-
43
- mutex = Mutex.new
44
- cv = ConditionVariable.new
45
-
46
- Thread.main[:ruote_amqp_connection] = Thread.new do
47
- Thread.abort_on_exception = true
48
- AMQP.start {
49
- started!
50
- cv.signal
51
- }
52
- end
53
-
54
- mutex.synchronize { cv.wait(mutex) }
55
-
56
- MQ.prefetch(1)
57
-
58
- yield if block_given?
59
- end
60
-
61
- # Check whether the AMQP connection is started
62
- def started?
63
- Thread.main[:ruote_amqp_started] == true
64
- end
65
-
66
- def started! #:nodoc:
67
- Thread.main[:ruote_amqp_started] = true
68
- end
69
-
70
- # Close down the AMQP connections
71
- def stop!
72
- return unless started?
73
-
74
- AMQP.stop
75
- Thread.main[:ruote_amqp_connection].join
76
- Thread.main[:ruote_amqp_started] = false
77
- end
78
- end
79
- end
2
+ require 'ruote/amqp'
80
3