ruote-amqp 2.1.5 → 2.2.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 → CHANGELOG.txt} +18 -4
- data/CREDITS.txt +29 -0
- data/README.rdoc +6 -6
- data/Rakefile +101 -50
- data/TODO.txt +7 -3
- data/lib/ruote-amqp.rb +8 -3
- data/lib/ruote-amqp/launchitem_listener.rb +10 -76
- data/lib/ruote-amqp/participant.rb +154 -99
- data/lib/ruote-amqp/receiver.rb +147 -0
- data/lib/ruote-amqp/version.rb +6 -0
- data/lib/ruote-amqp/workitem_listener.rb +5 -77
- data/ruote-amqp.gemspec +24 -75
- data/spec/launchitem_listener_spec.rb +49 -11
- data/spec/participant_spec.rb +71 -50
- data/spec/receiver_spec.rb +126 -0
- data/spec/ruote_amqp_spec.rb +9 -3
- data/spec/spec_helper.rb +18 -18
- data/spec/support/ruote_helpers.rb +29 -0
- data/{lib/spec → spec/support}/ruote_matchers.rb +14 -9
- data/spec/workitem_listener_spec.rb +30 -15
- metadata +90 -64
- data/.gitignore +0 -6
- data/Manifest.txt +0 -24
- data/lib/spec/ruote.rb +0 -5
- data/lib/spec/ruote_example_group.rb +0 -8
- data/lib/spec/ruote_helpers.rb +0 -27
- data/script/console +0 -10
- data/script/destroy +0 -14
- data/script/generate +0 -14
- data/spec/spec.opts +0 -1
@@ -1,22 +1,36 @@
|
|
1
|
-
|
1
|
+
|
2
|
+
= ruote-amqp
|
3
|
+
|
4
|
+
|
5
|
+
== ruote-amqp - 2.2.0 released 2011/03/01
|
6
|
+
|
7
|
+
- receiver : exposing #decode_workitem for overwriting
|
8
|
+
- options[:queue] patch by Mario Camou
|
9
|
+
- :durable path by belucid
|
10
|
+
- 1 MQ per dispatch thread 'leak' fix. Thanks weifeng365
|
11
|
+
- RuoteAMQP::Participant --> RuoteAMQP::ParticipantProxy
|
12
|
+
|
13
|
+
|
14
|
+
== 2.0.0 not released
|
2
15
|
|
3
16
|
* Compatible with ruote 2.0
|
4
17
|
* Thanks to John Mettraux (http://github.com/jmettraux/ruote-amqp)
|
5
18
|
* Thanks to Jason & Jordan (http://github.com/asm/ruote-amqp)
|
6
19
|
* Thanks to Charles Magid (http://github.com/ChasManRors/ruote-amqp)
|
7
20
|
|
8
|
-
|
21
|
+
== 0.9.21.1 2009-08-03
|
9
22
|
|
10
23
|
* Switch to using persistent AMQP messages by default
|
11
24
|
|
12
|
-
|
25
|
+
== 0.9.21 2009-07-13
|
13
26
|
|
14
27
|
* Depend on ruote-0.9.21 for flexible JSON backends
|
15
28
|
* Support for default queues
|
16
29
|
* Support for mapping participant names to queue names
|
17
30
|
* Plenty of RDOC fixed
|
18
31
|
|
19
|
-
|
32
|
+
== 0.9.20 2009-07-13
|
20
33
|
|
21
34
|
* 1 major enhancement:
|
22
35
|
* Initial release
|
36
|
+
|
data/CREDITS.txt
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
= CREDITS
|
3
|
+
|
4
|
+
(probably incomplete, don't hesitate to tell us if a mention is missing)
|
5
|
+
|
6
|
+
|
7
|
+
== AUTHORS
|
8
|
+
|
9
|
+
* Kenneth Kalmer - http://www.opensourcery.co.za/
|
10
|
+
* John Mettraux - https://github.com/jmettraux
|
11
|
+
|
12
|
+
|
13
|
+
== CONTRIBUTORS
|
14
|
+
|
15
|
+
* Mario Camou
|
16
|
+
* Sean Johnson - https://github.com/belucid
|
17
|
+
* Victor Liu - https://github.com/pennymax
|
18
|
+
* weifeng - https://github.com/weifeng365
|
19
|
+
* David Greaves - https://github.com/lbt
|
20
|
+
* Hartog C. de Mik - https://github.com/coffeeaddict
|
21
|
+
* Torsten Schoenebaum - https://github.com/tosch
|
22
|
+
* Jordan Ritter - https://github.com/jpr5
|
23
|
+
* Charles Magid - https://github.com/ChasManRors
|
24
|
+
* Marc Mauger - https://github.com/simianarmy
|
25
|
+
* Jason - https://github.com/asm
|
26
|
+
|
27
|
+
|
28
|
+
== FEEDBACK
|
29
|
+
|
data/README.rdoc
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
|
1
2
|
= ruote-amqp
|
2
3
|
|
3
4
|
* http://github.com/kennethkalmer/ruote-amqp
|
@@ -16,7 +17,7 @@ http://ruote.rubyforge.org/part_implementations.html
|
|
16
17
|
== FEATURES/PROBLEMS:
|
17
18
|
|
18
19
|
* Flexible participant for sending workitems
|
19
|
-
* Flexible
|
20
|
+
* Flexible receiver for receiving replies
|
20
21
|
* Flexible launch item listener for launching processes over AMQP
|
21
22
|
* Fully evented (thanks to the amqp gem)
|
22
23
|
|
@@ -26,9 +27,8 @@ Please review the rdoc in RuoteAMQP::Participant and Ruote::AMQP::Listener
|
|
26
27
|
|
27
28
|
== REQUIREMENTS:
|
28
29
|
|
29
|
-
* ruote[http://ruote.rubyforge.org] 2.
|
30
|
-
* amqp[http://github.com/tmm1/amqp] 0.6.
|
31
|
-
* rufus-json[http://github.com/jmettraux/rufus-json] 0.1.0 or later
|
30
|
+
* ruote[http://ruote.rubyforge.org] 2.2.0 or later
|
31
|
+
* amqp[http://github.com/tmm1/amqp] 0.6.7 or later
|
32
32
|
* rabbitmq[http://www.rabbitmq.com/] 1.6.0 or later
|
33
33
|
|
34
34
|
== INSTALL:
|
@@ -40,7 +40,7 @@ Please be sure to have read the requirements section above
|
|
40
40
|
== TESTS:
|
41
41
|
|
42
42
|
To run the tests you need the following requirements met, or the testing environment
|
43
|
-
will fail horribly.
|
43
|
+
will fail horribly (or simply get stuck without output).
|
44
44
|
|
45
45
|
=== RabbitMQ vhost
|
46
46
|
|
@@ -69,7 +69,7 @@ DaemonKit doesn't currently support ruote 2.1, support is forthcoming.
|
|
69
69
|
|
70
70
|
(The MIT License)
|
71
71
|
|
72
|
-
Copyright (c) 2010 Kenneth Kalmer
|
72
|
+
Copyright (c) 2010-2011 Kenneth Kalmer
|
73
73
|
|
74
74
|
Permission is hereby granted, free of charge, to any person obtaining
|
75
75
|
a copy of this software and associated documentation files (the
|
data/Rakefile
CHANGED
@@ -1,50 +1,101 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
require '
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
task :
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
1
|
+
|
2
|
+
$:.unshift('.') # 1.9.2
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'rubygems/user_interaction' if Gem::RubyGemsVersion == '1.5.0'
|
6
|
+
|
7
|
+
require 'rake'
|
8
|
+
require 'rake/clean'
|
9
|
+
require 'rake/rdoctask'
|
10
|
+
|
11
|
+
|
12
|
+
#
|
13
|
+
# clean
|
14
|
+
|
15
|
+
CLEAN.include('pkg', 'rdoc')
|
16
|
+
|
17
|
+
|
18
|
+
#
|
19
|
+
# test / spec
|
20
|
+
|
21
|
+
task :spec do
|
22
|
+
|
23
|
+
sh 'rspec spec/'
|
24
|
+
end
|
25
|
+
|
26
|
+
task :test => [ :spec ]
|
27
|
+
task :default => [ :spec ]
|
28
|
+
|
29
|
+
|
30
|
+
#
|
31
|
+
# gem
|
32
|
+
|
33
|
+
GEMSPEC_FILE = Dir['*.gemspec'].first
|
34
|
+
GEMSPEC = eval(File.read(GEMSPEC_FILE))
|
35
|
+
GEMSPEC.validate
|
36
|
+
|
37
|
+
|
38
|
+
desc %{
|
39
|
+
builds the gem and places it in pkg/
|
40
|
+
}
|
41
|
+
task :build do
|
42
|
+
|
43
|
+
sh "gem build #{GEMSPEC_FILE}"
|
44
|
+
sh "mkdir pkg" rescue nil
|
45
|
+
sh "mv #{GEMSPEC.name}-#{GEMSPEC.version}.gem pkg/"
|
46
|
+
end
|
47
|
+
|
48
|
+
desc %{
|
49
|
+
builds the gem and pushes it to rubygems.org
|
50
|
+
}
|
51
|
+
task :push => :build do
|
52
|
+
|
53
|
+
sh "gem push pkg/#{GEMSPEC.name}-#{GEMSPEC.version}.gem"
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
#
|
58
|
+
# rabbitmq preparation
|
59
|
+
|
60
|
+
desc %{
|
61
|
+
prepare RabbitMQ (vhost, user, perms)
|
62
|
+
}
|
63
|
+
task :prepare do
|
64
|
+
|
65
|
+
sh "rabbitmqctl add_vhost ruote-test"
|
66
|
+
sh "rabbitmqctl add_user ruote ruote"
|
67
|
+
sh "rabbitmqctl set_permissions -p ruote-test ruote '.*' '.*' '.*'"
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
#
|
72
|
+
# rdoc
|
73
|
+
#
|
74
|
+
# make sure to have rdoc 2.5.x to run that
|
75
|
+
|
76
|
+
Rake::RDocTask.new do |rd|
|
77
|
+
|
78
|
+
rd.main = 'README.rdoc'
|
79
|
+
rd.rdoc_dir = 'rdoc'
|
80
|
+
|
81
|
+
rd.rdoc_files.include(
|
82
|
+
'README.rdoc', 'CHANGELOG.txt', 'CREDITS.txt', 'lib/**/*.rb')
|
83
|
+
|
84
|
+
rd.title = "#{GEMSPEC.name} #{GEMSPEC.version}"
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
#
|
89
|
+
# upload_rdoc
|
90
|
+
|
91
|
+
desc %{
|
92
|
+
upload the rdoc to rubyforge
|
93
|
+
}
|
94
|
+
task :upload_rdoc => [ :clean, :rdoc ] do
|
95
|
+
|
96
|
+
account = 'jmettraux@rubyforge.org'
|
97
|
+
webdir = '/var/www/gforge-projects/ruote'
|
98
|
+
|
99
|
+
sh "rsync -azv -e ssh rdoc/#{GEMSPEC.name}_rdoc #{account}:#{webdir}/"
|
100
|
+
end
|
101
|
+
|
data/TODO.txt
CHANGED
@@ -1,4 +1,8 @@
|
|
1
|
-
ruote-amqp TODO
|
2
|
-
===============
|
3
1
|
|
4
|
-
[
|
2
|
+
[o] Launch processes over AMQP (LaunchitemListener)
|
3
|
+
[o] Receiver
|
4
|
+
[o] ParticipantProxy ?
|
5
|
+
|
6
|
+
[ ] have a class method ParticipantProxy.stop_all ?
|
7
|
+
[ ] use Ruote::Workitem #as_json and #from_json(s)
|
8
|
+
|
data/lib/ruote-amqp.rb
CHANGED
@@ -1,5 +1,10 @@
|
|
1
|
+
|
1
2
|
require 'mq'
|
2
3
|
|
4
|
+
require 'ruote-amqp/version'
|
5
|
+
|
6
|
+
|
7
|
+
#
|
3
8
|
# AMQP participant and listener pair for ruote.
|
4
9
|
#
|
5
10
|
# == Documentation
|
@@ -15,9 +20,9 @@ require 'mq'
|
|
15
20
|
#
|
16
21
|
module RuoteAMQP
|
17
22
|
|
18
|
-
|
23
|
+
autoload 'ParticipantProxy', 'ruote-amqp/participant'
|
19
24
|
|
20
|
-
autoload '
|
25
|
+
autoload 'Receiver', 'ruote-amqp/receiver'
|
21
26
|
autoload 'WorkitemListener', 'ruote-amqp/workitem_listener'
|
22
27
|
autoload 'LaunchitemListener', 'ruote-amqp/launchitem_listener'
|
23
28
|
|
@@ -70,6 +75,6 @@ module RuoteAMQP
|
|
70
75
|
Thread.main[:ruote_amqp_connection].join
|
71
76
|
Thread.main[:ruote_amqp_started] = false
|
72
77
|
end
|
73
|
-
|
74
78
|
end
|
75
79
|
end
|
80
|
+
|
@@ -1,88 +1,22 @@
|
|
1
|
+
|
1
2
|
module RuoteAMQP
|
2
3
|
|
3
|
-
# = AMQP Launchitem Listener
|
4
|
-
#
|
5
|
-
# Used on its own, the RuoteAMQP::LaunchitemListener provides the engine with
|
6
|
-
# a way to launch process definitions over an AMQP direct exchange.
|
7
|
-
#
|
8
|
-
# == Message Format
|
9
|
-
#
|
10
|
-
# The LaunchitemListener expects JSON formatted messages that look like this:
|
11
|
-
#
|
12
|
-
# {
|
13
|
-
# "definition" : "process definition",
|
14
|
-
# "fields" : { "key" : "value" },
|
15
|
-
# "variables" : { "key" : "value" }
|
16
|
-
# }
|
17
|
-
#
|
18
|
-
# The definition key is a complete string representation of a business process.
|
19
|
-
#
|
20
|
-
# == Configuration
|
21
4
|
#
|
22
|
-
#
|
23
|
-
# +AMQP.settings+ hash, as provided by the AMQP gem. No defaults are set by
|
24
|
-
# the listener. The only +option+ parsed by the initializer is the +queue+
|
25
|
-
# key (in the optional hash). If no +queue+ key is provided, the listener
|
26
|
-
# will subscribe to the +ruote_launchitems+ direct exchange for launchitems.
|
5
|
+
# Got replaced by RuoteAMQP::Receiver
|
27
6
|
#
|
28
|
-
#
|
7
|
+
# This class is kept for backward compatibility.
|
29
8
|
#
|
30
|
-
|
31
|
-
#
|
32
|
-
# Register the engine with the listener:
|
33
|
-
#
|
34
|
-
# RuoteAMQP::LaunchitemListener.new( engine_instance )
|
35
|
-
#
|
36
|
-
# The workitem listener leverages the asynchronous nature of the amqp gem,
|
37
|
-
# so no timers are setup when initialized.
|
38
|
-
class LaunchitemListener < Ruote::Receiver
|
39
|
-
|
40
|
-
class << self
|
41
|
-
|
42
|
-
# Listening queue - set this before initialization
|
43
|
-
attr_writer :queue
|
44
|
-
|
45
|
-
def queue
|
46
|
-
@queue ||= 'ruote_launchitems'
|
47
|
-
end
|
48
|
-
|
49
|
-
end
|
9
|
+
class LaunchitemListener < ::RuoteAMQP::Receiver
|
50
10
|
|
51
11
|
# Start a new LaunchItem listener
|
52
12
|
#
|
53
|
-
# @param [ Ruote::Engine ]
|
54
|
-
# @param
|
55
|
-
|
56
|
-
|
57
|
-
self.class.queue = queue if queue
|
58
|
-
|
59
|
-
RuoteAMQP.start!
|
60
|
-
|
61
|
-
MQ.queue( self.class.queue, :durable => true ).subscribe do |message|
|
62
|
-
if AMQP.closing?
|
63
|
-
# Do nothing, we're going down
|
64
|
-
else
|
65
|
-
launchitem = decode_launchitem( message )
|
66
|
-
engine.launch( *launchitem )
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def stop
|
72
|
-
RuoteAMQP.stop!
|
73
|
-
end
|
74
|
-
|
75
|
-
private
|
76
|
-
|
77
|
-
# Complicated guesswork that needs to happen here to detect the format
|
78
|
-
def decode_launchitem( msg )
|
79
|
-
hash = Rufus::Json.decode( msg )
|
80
|
-
opts = {}
|
81
|
-
definition = hash.delete('definition')
|
82
|
-
fields = hash.delete('fields') || {}
|
83
|
-
variables = hash.delete('variables') || {}
|
13
|
+
# @param [ Ruote::Engine, Ruote::Storage ] A configured ruote engine or storage instance
|
14
|
+
# @param opts :queue / :unsubscribe
|
15
|
+
#
|
16
|
+
def initialize(engine_or_storage, opts={})
|
84
17
|
|
85
|
-
|
18
|
+
super(engine_or_storage, opts.merge(:launchitems => :only))
|
86
19
|
end
|
87
20
|
end
|
88
21
|
end
|
22
|
+
|
@@ -1,19 +1,37 @@
|
|
1
|
+
|
1
2
|
require 'ruote/part/local_participant'
|
3
|
+
require 'ruote-amqp'
|
4
|
+
|
2
5
|
|
3
6
|
module RuoteAMQP
|
4
7
|
|
8
|
+
#
|
5
9
|
# = AMQP Participants
|
6
10
|
#
|
7
|
-
# The RuoteAMQP::
|
11
|
+
# The RuoteAMQP::ParticipantProxy allows you to send workitems (serialized as
|
8
12
|
# JSON) or messages to any AMQP queues right from the process
|
9
|
-
# definition. When combined with the RuoteAMQP::
|
13
|
+
# definition. When combined with the RuoteAMQP::Receiver you can easily
|
10
14
|
# leverage an extremely powerful local/remote participant
|
11
15
|
# combinations.
|
12
16
|
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
+
# For local/remote participants The local part of the
|
18
|
+
# RuoteAMQP::ParticipantProxy relies on the presence of a
|
19
|
+
# RuoteAMQP::Receiver. Workitems are sent to the remote participant
|
20
|
+
# and the local part does not normally reply to the engine. Instead
|
21
|
+
# the engine will continue when a reply is received on the
|
22
|
+
# 'ruote_workitems' queue (see RuoteAMQP::Receiver).
|
23
|
+
#
|
24
|
+
# Of course, the standard :forget => true format can be used even
|
25
|
+
# with remote particpants and :forget can even be set as a default in
|
26
|
+
# the options.
|
27
|
+
#
|
28
|
+
# A simple way to create a remote participant to act upon workitems
|
29
|
+
# is to use the daemon-kit ruote responder.
|
30
|
+
#
|
31
|
+
# Simple AMQP messages are treated as 'fire and forget' and the flow
|
32
|
+
# will continue when the local participant has queued the message
|
33
|
+
# for sending. (As there is no meaningful way to receive a workitem
|
34
|
+
# in reply).
|
17
35
|
#
|
18
36
|
# == Configuration
|
19
37
|
#
|
@@ -21,86 +39,59 @@ module RuoteAMQP
|
|
21
39
|
# values of the +AMQP.settings+ hash, as provided by the AMQP
|
22
40
|
# gem. No AMQP defaults are set by the participant.
|
23
41
|
#
|
24
|
-
# The participant requires version 0.6.1 or later of the amqp gem.
|
25
|
-
#
|
26
42
|
# == Usage
|
27
43
|
#
|
28
|
-
#
|
29
|
-
# directly to a specific queue, and have the engine wait for
|
30
|
-
# replies on another queue (see AMQPListener).
|
31
|
-
#
|
32
|
-
# Setting up the participant
|
44
|
+
# Define the queue used by an AMQP participant :
|
33
45
|
#
|
34
46
|
# engine.register_participant(
|
35
|
-
# :
|
47
|
+
# :delete_user, RuoteAMQP::ParticipantProxy, 'queue' => 'user_manager')
|
36
48
|
#
|
37
|
-
#
|
49
|
+
# Sending a workitem to the remote participant defined above:
|
38
50
|
#
|
39
|
-
#
|
40
|
-
# :amqp, RuoteAMQP::Participant.new(:reply_by_default => true ) )
|
41
|
-
#
|
42
|
-
# Sending a message example
|
43
|
-
#
|
44
|
-
# class AmqpMessageExample0 < OpenWFE::ProcessDefinition
|
51
|
+
# Ruote.process_definition do
|
45
52
|
# sequence do
|
46
|
-
#
|
53
|
+
# delete_user
|
47
54
|
# end
|
48
55
|
# end
|
49
56
|
#
|
50
|
-
#
|
57
|
+
# Let the local participant reply to the engine without involving
|
58
|
+
# the receiver
|
51
59
|
#
|
52
|
-
#
|
60
|
+
# Ruote.process_definition do
|
53
61
|
# sequence do
|
54
|
-
#
|
62
|
+
# delete_user :forget => true
|
55
63
|
# end
|
56
64
|
# end
|
57
65
|
#
|
58
|
-
#
|
66
|
+
# Setting up the participant in a slightly more 'raw' way:
|
67
|
+
#
|
68
|
+
# engine.register_participant(
|
69
|
+
# :amqp, RuoteAMQP::ParticipantProxy )
|
70
|
+
#
|
71
|
+
# Sending a workitem to a specific queue:
|
59
72
|
#
|
60
|
-
#
|
73
|
+
# Ruote.process_definition do
|
61
74
|
# sequence do
|
62
|
-
# amqp :queue => 'test',
|
75
|
+
# amqp :queue => 'test', 'command' => '/run/regression_test'
|
63
76
|
# end
|
64
77
|
# end
|
65
78
|
#
|
66
|
-
#
|
67
|
-
#
|
68
|
-
# Keeping things DRY with participant name to queue maps:
|
69
|
-
#
|
70
|
-
# amqp = RuoteAMQP::Participant.new( :default_queue => 'test' )
|
71
|
-
# amqp.map_participant 'george', 'whitehouse'
|
72
|
-
# amqp.map_participant 'barak', 'whitehouse'
|
73
|
-
# amqp.map_participant 'greenspan', 'treasury'
|
79
|
+
# Setup a 'fire and forget' participant that always replies to the
|
80
|
+
# engine:
|
74
81
|
#
|
75
|
-
# engine.register_participant(
|
76
|
-
#
|
77
|
-
# engine.register_participant( :greespan, amqp )
|
78
|
-
# engine.register_participant( :amqp, amqp )
|
79
|
-
#
|
80
|
-
# class DryAmqProcess0 < OpenWFE::ProcessDefinition
|
81
|
-
# cursor :break_if => "${f:economy_recovered}" do
|
82
|
-
# # Workitem sent to 'whitehouse' queue
|
83
|
-
# george :activity => 'Tank economy'
|
84
|
-
#
|
85
|
-
# # Workitem sent to 'treasury' queue
|
86
|
-
# greenspan :activity => 'Resign'
|
82
|
+
# engine.register_participant(
|
83
|
+
# :jfdi, RuoteAMQP::ParticipantProxy, 'forget' => true )
|
87
84
|
#
|
88
|
-
#
|
89
|
-
#
|
85
|
+
# Sending a message example to a specific queue (both steps are
|
86
|
+
# equivalent):
|
90
87
|
#
|
91
|
-
#
|
92
|
-
#
|
88
|
+
# Ruote.process_definition do
|
89
|
+
# sequence do
|
90
|
+
# amqp :queue => 'test', :message => 'foo'
|
91
|
+
# amqp :queue => 'test', :message => 'foo', :forget => true
|
93
92
|
# end
|
94
93
|
# end
|
95
94
|
#
|
96
|
-
# == Workitem modifications
|
97
|
-
#
|
98
|
-
# To ease replies, and additional workitem attribute is set:
|
99
|
-
#
|
100
|
-
# 'reply_queue'
|
101
|
-
#
|
102
|
-
# +reply_queue+ has the name of the queue where the RuoteAMQP::Listener
|
103
|
-
# expects replies from remote participants
|
104
95
|
#
|
105
96
|
# == AMQP notes
|
106
97
|
#
|
@@ -112,27 +103,33 @@ module RuoteAMQP
|
|
112
103
|
# participant, and messages are marked as persistent by default (see
|
113
104
|
# #RuoteAMQP)
|
114
105
|
#
|
115
|
-
class
|
106
|
+
class ParticipantProxy
|
116
107
|
|
117
108
|
include Ruote::LocalParticipant
|
118
109
|
|
119
|
-
#
|
110
|
+
# The following parameters are used in the process definition.
|
120
111
|
#
|
121
|
-
#
|
122
|
-
#
|
123
|
-
|
112
|
+
# An options hash with the same keys to provide defaults is
|
113
|
+
# accepted at registration time (see above).
|
114
|
+
#
|
115
|
+
# * :queue => (string) The AMQP queue used by the remote participant.
|
116
|
+
# nil by default.
|
117
|
+
# * :forget => (bool) Whether the flow should block until the remote
|
118
|
+
# participant replies.
|
119
|
+
# false by default
|
120
|
+
#
|
121
|
+
def initialize(options)
|
122
|
+
|
124
123
|
RuoteAMQP.start!
|
125
124
|
|
126
125
|
@options = {
|
127
|
-
|
128
|
-
|
129
|
-
}.merge(
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
def map_participant( name, queue )
|
135
|
-
@participant_maps[ name ] = queue
|
126
|
+
'queue' => nil,
|
127
|
+
'forget' => false,
|
128
|
+
}.merge(options.inject({}) { |h, (k, v)|
|
129
|
+
h[k.to_s] = v; h
|
130
|
+
})
|
131
|
+
#
|
132
|
+
# the inject is here to make sure that all options have String keys
|
136
133
|
end
|
137
134
|
|
138
135
|
# Process the workitem at hand. By default the workitem will be
|
@@ -140,47 +137,105 @@ module RuoteAMQP
|
|
140
137
|
# workitem parameter. You can specify a +message+ workitem
|
141
138
|
# parameter to have that sent instead of the workitem.
|
142
139
|
#
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
140
|
+
def consume(workitem)
|
141
|
+
|
142
|
+
target_queue = determine_queue(workitem)
|
143
|
+
|
144
|
+
raise 'no queue specified (outbound delivery)' unless target_queue
|
145
|
+
|
146
|
+
q = MQ.queue(target_queue, :durable => true)
|
147
|
+
forget = determine_forget(workitem)
|
148
|
+
|
149
|
+
opts = {
|
150
|
+
:persistent => RuoteAMQP.use_persistent_messages?,
|
151
|
+
:content_type => 'application/json' }
|
152
|
+
|
153
|
+
if message = workitem.fields['message'] || workitem.params['message']
|
154
|
+
|
155
|
+
forget = true # sending a message implies 'forget' => true
|
156
|
+
|
157
|
+
q.publish(message, opts)
|
158
|
+
|
156
159
|
else
|
157
|
-
raise "no queue in workitem params!"
|
158
|
-
end
|
159
160
|
|
160
|
-
|
161
|
-
reply_to_engine( workitem )
|
161
|
+
q.publish(encode_workitem(workitem), opts)
|
162
162
|
end
|
163
|
+
|
164
|
+
reply_to_engine(workitem) if forget
|
163
165
|
end
|
164
166
|
|
167
|
+
# (Stops the underlying queue subscription)
|
168
|
+
#
|
165
169
|
def stop
|
170
|
+
|
166
171
|
RuoteAMQP.stop!
|
167
172
|
end
|
168
173
|
|
169
174
|
def cancel(fei, flavour)
|
175
|
+
#
|
176
|
+
# TODO : sending a cancel item is not a bad idea, especially if the
|
177
|
+
# job done over the amqp fence lasts...
|
178
|
+
#
|
179
|
+
end
|
180
|
+
|
181
|
+
# The current AMQP (0.6.7) has 1 queue per thread. If you let the default
|
182
|
+
# "one thread per participant consume call" kick in, you'll end up with
|
183
|
+
# 1 queue per consume call (and...)
|
184
|
+
#
|
185
|
+
# So, by returning true here, we force the queue to be always the same.
|
186
|
+
#
|
187
|
+
# Many thanks to https://github.com/weifeng365 for reporting this issue
|
188
|
+
# and suggesting the fix.
|
189
|
+
#
|
190
|
+
# TODO : should we have something to close queues when the engine / worker
|
191
|
+
# shuts down ?
|
192
|
+
# or is it already covered in the #stop ?
|
193
|
+
#
|
194
|
+
def do_not_thread
|
195
|
+
|
196
|
+
true
|
170
197
|
end
|
171
198
|
|
172
199
|
private
|
173
200
|
|
174
|
-
def
|
175
|
-
|
176
|
-
|
177
|
-
@options[
|
201
|
+
def determine_forget(workitem)
|
202
|
+
|
203
|
+
return workitem.params['forget'] if workitem.params.has_key?('forget')
|
204
|
+
return @options['forget'] if @options.has_key?('forget')
|
205
|
+
false
|
206
|
+
end
|
207
|
+
|
208
|
+
def determine_queue(workitem)
|
209
|
+
|
210
|
+
workitem.params['queue'] || @options['queue']
|
211
|
+
end
|
212
|
+
|
213
|
+
# Encodes the workitem as JSON. Makes sure to add to the field 'params'
|
214
|
+
# an entry named 'participant_options' which contains the options of
|
215
|
+
# this participant.
|
216
|
+
#
|
217
|
+
def encode_workitem(wi)
|
218
|
+
|
219
|
+
wi.params['participant_options'] = @options
|
220
|
+
|
221
|
+
Rufus::Json.encode(wi.to_h)
|
178
222
|
end
|
223
|
+
end
|
224
|
+
|
225
|
+
#
|
226
|
+
# Kept for backward compatibility.
|
227
|
+
#
|
228
|
+
# You should use RuoteAMQP::ParticipantProxy.
|
229
|
+
#
|
230
|
+
class Participant < ParticipantProxy
|
179
231
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
232
|
+
def initialize(options)
|
233
|
+
puts '=' * 80
|
234
|
+
puts "RuoteAMQP::Participant will be deprecated soon (2.1.12)"
|
235
|
+
puts "please use RuoteAMQP::ParticipantProxy instead"
|
236
|
+
puts '=' * 80
|
237
|
+
super
|
184
238
|
end
|
185
239
|
end
|
186
240
|
end
|
241
|
+
|