ruote-amqp 0.9.21.1 → 2.1.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,84 @@
1
+ module RuoteAMQP
2
+
3
+ #
4
+ # = AMQP Workitem Listener
5
+ #
6
+ # Used in conjunction with the RuoteAMQP::Participant, the WorkitemListener
7
+ # subscribes to a specific direct exchange and monitors for
8
+ # incoming workitems. It expects workitems to arrive serialized as
9
+ # JSON.
10
+ #
11
+ # == Configuration
12
+ #
13
+ # AMQP configuration is handled by directly manipulating the values of
14
+ # the +AMQP.settings+ hash, as provided by the AMQP gem. No
15
+ # defaults are set by the listener. The only +option+ parsed by
16
+ # the initializer of the workitem listener is the +queue+ key (Hash
17
+ # expected). If no +queue+ key is set, the listener will subscribe
18
+ # to the +ruote_workitems+ direct exchange for workitems, otherwise it will
19
+ # subscribe to the direct exchange provided.
20
+ #
21
+ # The participant requires version 0.6.6 or later of the amqp gem.
22
+ #
23
+ # == Usage
24
+ #
25
+ # Register the engine or storage with the listener:
26
+ #
27
+ # RuoteAMQP::WorkitemListener.new( engine_or_storage )
28
+ #
29
+ # The workitem listener leverages the asynchronous nature of the amqp gem,
30
+ # so no timers are setup when initialized.
31
+ #
32
+ # See the RuoteAMQP::Participant docs for information on sending
33
+ # workitems out to remote participants, and have them send replies
34
+ # to the correct direct exchange specified in the workitem
35
+ # attributes.
36
+ #
37
+ class WorkitemListener < Ruote::Receiver
38
+
39
+ class << self
40
+
41
+ # Listening queue - set this before initialization
42
+ attr_writer :queue
43
+
44
+ def queue
45
+ @queue ||= 'ruote_workitems'
46
+ end
47
+
48
+ end
49
+
50
+ # Starts a new WorkitemListener
51
+ #
52
+ # @param [ Ruote::Engine, Ruote::Storage ] A configured ruote engine or storage instance
53
+ # @param [ String ] An optional queue name
54
+ def initialize( engine_or_storage, queue = nil )
55
+
56
+ @storage = engine_or_storage.respond_to?( :storage ) ? engine_or_storage.storage : engine_or_storage
57
+
58
+ self.class.queue = queue if queue
59
+
60
+ RuoteAMQP.start!
61
+
62
+ MQ.queue( self.class.queue, :durable => true ).subscribe do |message|
63
+ if AMQP.closing?
64
+ # Do nothing, we're going down
65
+ else
66
+ workitem = decode_workitem( message )
67
+ reply( workitem )
68
+ end
69
+ end
70
+ end
71
+
72
+ def stop
73
+ RuoteAMQP.stop!
74
+ end
75
+
76
+ private
77
+
78
+ # Complicated guesswork that needs to happen here to detect the format
79
+ def decode_workitem( msg )
80
+ hash = Rufus::Json.decode( msg )
81
+ Ruote::Workitem.new( hash )
82
+ end
83
+ end
84
+ end
data/lib/spec/ruote.rb CHANGED
@@ -2,4 +2,4 @@ require File.dirname(__FILE__) + '/ruote_example_group.rb'
2
2
  require File.dirname(__FILE__) + '/ruote_matchers.rb'
3
3
  require File.dirname(__FILE__) + '/ruote_helpers.rb'
4
4
 
5
- Spec::Example::ExampleGroupFactory.register(:ruote, Spec::Ruote::Example::RuoteExampleGroup)
5
+ Spec::Example::ExampleGroupFactory.register(:ruote, Spec::RuoteSpec::Example::RuoteExampleGroup)
@@ -1,5 +1,5 @@
1
1
  module Spec
2
- module Ruote
2
+ module RuoteSpec
3
3
  module Example
4
4
  class RuoteExampleGroup < Spec::Example::ExampleGroup
5
5
  end
@@ -1,14 +1,18 @@
1
+
1
2
  module RuoteSpecHelpers
2
3
 
3
4
  def purge_engine
4
- @engine.application_context.values.each do |s|
5
- s.purge if s.respond_to?(:purge)
6
- end
5
+
6
+ #@engine.context.values.each do |s|
7
+ # s.purge if s.respond_to?(:purge)
8
+ #end
7
9
  end
8
10
 
9
11
  def run_definition( pdef )
10
- fei = @engine.launch( pdef )
11
- wait( fei )
12
+
13
+ wfid = @engine.launch( pdef )
14
+
15
+ @engine.context.logger.wait_for( wfid )
12
16
 
13
17
  @engine.should_not have_errors
14
18
  @engine.should_not have_remaining_expressions
@@ -16,9 +20,8 @@ module RuoteSpecHelpers
16
20
  purge_engine
17
21
  end
18
22
 
19
- def wait( fei )
20
- Thread.pass
21
- return if @terminated_processes.include?( fei.wfid )
22
- @engine.wait_for( fei )
23
+ def noisy( on = true )
24
+ @engine.context.logger.noisy = on
23
25
  end
24
26
  end
27
+
@@ -1,16 +1,15 @@
1
+
1
2
  Spec::Matchers.define :have_errors do |*args|
3
+
2
4
  match do |engine|
3
- @ps = if fei = args.shift
4
- engine.process_status( fei )
5
- else
6
- engine.process_statuses.values.first
7
- end
8
5
 
9
- if @ps
10
- @ps.errors.size != 0
6
+ @ps = if wfid = args.shift
7
+ engine.processes( wfid )
11
8
  else
12
- false
9
+ engine.processes.first
13
10
  end
11
+
12
+ @ps ? (@ps.errors.size != 0) : false
14
13
  end
15
14
 
16
15
  failure_message_for_should do |engine|
@@ -18,9 +17,10 @@ Spec::Matchers.define :have_errors do |*args|
18
17
  end
19
18
  failure_message_for_should_not do |engine|
20
19
  "Expected the engine to not have errors, but it did.\n" +
21
- @ps.errors.values.map do |e|
22
- " * error: #{e.error_class} \"#{e.stacktrace}\""
23
- end.join("\n")
20
+ @ps.errors.map { |e|
21
+ " * error: #{e.error_class} #{e.error_message} " +
22
+ "\n\"#{e.error_backtrace.join("\n")}\""
23
+ }.join("\n")
24
24
  end
25
25
  description do
26
26
  #
@@ -28,29 +28,19 @@ Spec::Matchers.define :have_errors do |*args|
28
28
  end
29
29
 
30
30
  Spec::Matchers.define :have_remaining_expressions do
31
+
31
32
  match do |engine|
32
- exp_count = engine.get_expression_storage.size
33
33
 
34
- if exp_count == 1
35
- false
36
- else
37
- 50.times { Thread.pass }
38
- exp_count = engine.get_expression_storage.size
39
- if exp_count == 1
40
- false
41
- else
42
- true
43
- end
44
- end
34
+ (engine.storage.get_many('expressions').size != 0)
45
35
  end
46
36
 
47
37
  failure_message_for_should do |engine|
48
38
  "Expected engine to have processes remaining, but it didn't"
49
39
  end
50
40
  failure_message_for_should_not do |engine|
51
- "Expected engine to have no processes remaining, but it did.#{engine.get_expression_storage.to_s}"
41
+ "Expected engine to have no processes remaining, but it did.#{engine.storage.get_many('expressions').inspect}"
52
42
  end
53
43
  description do
54
-
55
44
  end
56
45
  end
46
+
@@ -0,0 +1,83 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{ruote-amqp}
8
+ s.version = "2.1.5"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["kenneth.kalmer@gmail.com"]
12
+ s.date = %q{2010-02-04}
13
+ s.email = %q{kenneth.kalmer@gmail.com}
14
+ s.extra_rdoc_files = [
15
+ "History.txt",
16
+ "Manifest.txt",
17
+ "PostInstall.txt",
18
+ "README.rdoc",
19
+ "TODO.txt"
20
+ ]
21
+ s.files = [
22
+ ".gitignore",
23
+ "History.txt",
24
+ "Manifest.txt",
25
+ "PostInstall.txt",
26
+ "README.rdoc",
27
+ "Rakefile",
28
+ "TODO.txt",
29
+ "lib/ruote-amqp.rb",
30
+ "lib/ruote-amqp/launchitem_listener.rb",
31
+ "lib/ruote-amqp/participant.rb",
32
+ "lib/ruote-amqp/workitem_listener.rb",
33
+ "lib/spec/ruote.rb",
34
+ "lib/spec/ruote_example_group.rb",
35
+ "lib/spec/ruote_helpers.rb",
36
+ "lib/spec/ruote_matchers.rb",
37
+ "ruote-amqp.gemspec",
38
+ "script/console",
39
+ "script/destroy",
40
+ "script/generate",
41
+ "spec/launchitem_listener_spec.rb",
42
+ "spec/participant_spec.rb",
43
+ "spec/ruote_amqp_spec.rb",
44
+ "spec/spec.opts",
45
+ "spec/spec_helper.rb",
46
+ "spec/workitem_listener_spec.rb"
47
+ ]
48
+ s.homepage = %q{http://github.com/kennethkalmer/ruote-amqp}
49
+ s.rdoc_options = ["--charset=UTF-8"]
50
+ s.require_paths = ["lib"]
51
+ s.rubygems_version = %q{1.3.5}
52
+ s.summary = %q{AMQP participant/listener pair for ruote 2.1}
53
+ s.test_files = [
54
+ "spec/launchitem_listener_spec.rb",
55
+ "spec/participant_spec.rb",
56
+ "spec/ruote_amqp_spec.rb",
57
+ "spec/spec_helper.rb",
58
+ "spec/workitem_listener_spec.rb"
59
+ ]
60
+
61
+ if s.respond_to? :specification_version then
62
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
63
+ s.specification_version = 3
64
+
65
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
66
+ s.add_runtime_dependency(%q<rufus-json>, [">= 0.1.0"])
67
+ s.add_runtime_dependency(%q<amqp>, [">= 0.6.6"])
68
+ s.add_runtime_dependency(%q<ruote>, [">= 2.1.5"])
69
+ s.add_development_dependency(%q<rspec>, [">= 0"])
70
+ else
71
+ s.add_dependency(%q<rufus-json>, [">= 0.1.0"])
72
+ s.add_dependency(%q<amqp>, [">= 0.6.6"])
73
+ s.add_dependency(%q<ruote>, [">= 2.1.5"])
74
+ s.add_dependency(%q<rspec>, [">= 0"])
75
+ end
76
+ else
77
+ s.add_dependency(%q<rufus-json>, [">= 0.1.0"])
78
+ s.add_dependency(%q<amqp>, [">= 0.6.6"])
79
+ s.add_dependency(%q<ruote>, [">= 2.1.5"])
80
+ s.add_dependency(%q<rspec>, [">= 0"])
81
+ end
82
+ end
83
+
@@ -0,0 +1,32 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe RuoteAMQP::LaunchitemListener do
4
+
5
+ it "should launch processes" do
6
+ json = {
7
+ "definition" => "
8
+ Ruote.process_definition :name => 'test' do
9
+ sequence do
10
+ echo '${f:foo}'
11
+ end
12
+ end
13
+ ",
14
+ "fields" => {
15
+ "foo" => "bar"
16
+ }
17
+ }.to_json
18
+
19
+ RuoteAMQP::LaunchitemListener.new( @engine )
20
+
21
+ MQ.queue( RuoteAMQP::LaunchitemListener.queue ).publish( json )
22
+
23
+ sleep 0.5
24
+
25
+ @engine.should_not have_errors
26
+ @engine.should_not have_remaining_expressions
27
+
28
+ @tracer.to_s.should == "bar"
29
+
30
+ purge_engine
31
+ end
32
+ end
@@ -4,15 +4,12 @@ describe RuoteAMQP::Participant, :type => :ruote do
4
4
 
5
5
  it "should support 'reply anyway' on expression parameter" do
6
6
 
7
- pdef = <<-EOF
8
- class AmqpParticipant0 < OpenWFE::ProcessDefinition
9
-
7
+ pdef = ::Ruote.process_definition :name => 'test' do
10
8
  sequence do
11
9
  amqp :queue => 'test1', 'reply_anyway' => true
12
10
  echo 'done.'
13
11
  end
14
12
  end
15
- EOF
16
13
 
17
14
  @engine.register_participant( :amqp, RuoteAMQP::Participant )
18
15
 
@@ -38,15 +35,13 @@ describe RuoteAMQP::Participant, :type => :ruote do
38
35
  end
39
36
 
40
37
  it "should support 'reply anyway' as participant configuration" do
41
- pdef = <<-EOF
42
- class AmqpParticipant0 < OpenWFE::ProcessDefinition
43
38
 
39
+ pdef = ::Ruote.process_definition :name => 'test' do
44
40
  sequence do
45
41
  amqp :queue => 'test4'
46
42
  echo 'done.'
47
43
  end
48
44
  end
49
- EOF
50
45
 
51
46
  p = RuoteAMQP::Participant.new( :reply_by_default => true )
52
47
  @engine.register_participant( :amqp, p )
@@ -56,7 +51,7 @@ describe RuoteAMQP::Participant, :type => :ruote do
56
51
  @tracer.to_s.should == "done."
57
52
 
58
53
  begin
59
- Timeout::timeout(10) do
54
+ Timeout::timeout(5) do
60
55
  @msg = nil
61
56
  MQ.queue('test4').subscribe { |msg| @msg = msg }
62
57
 
@@ -73,15 +68,13 @@ describe RuoteAMQP::Participant, :type => :ruote do
73
68
  end
74
69
 
75
70
  it "should support custom messages instead of workitems" do
76
- pdef = <<-EOF
77
- class AmqpParticipant1 < OpenWFE::ProcessDefinition
78
71
 
72
+ pdef = ::Ruote.process_definition :name => 'test' do
79
73
  sequence do
80
74
  amqp :queue => 'test2', :message => 'foo', 'reply_anyway' => true
81
75
  echo 'done.'
82
76
  end
83
77
  end
84
- EOF
85
78
 
86
79
  @engine.register_participant( :amqp, RuoteAMQP::Participant )
87
80
 
@@ -90,7 +83,7 @@ describe RuoteAMQP::Participant, :type => :ruote do
90
83
  @tracer.to_s.should == "done."
91
84
 
92
85
  begin
93
- Timeout::timeout(10) do
86
+ Timeout::timeout(5) do
94
87
  @msg = nil
95
88
  MQ.queue('test2').subscribe { |msg| @msg = msg }
96
89
 
@@ -108,15 +101,12 @@ describe RuoteAMQP::Participant, :type => :ruote do
108
101
 
109
102
  it "should support a default queue name" do
110
103
 
111
- pdef = <<-EOF
112
- class AmqpParticipant0 < OpenWFE::ProcessDefinition
113
-
104
+ pdef = ::Ruote.process_definition :name => 'test' do
114
105
  sequence do
115
106
  amqp 'reply_anyway' => true
116
107
  echo 'done.'
117
108
  end
118
109
  end
119
- EOF
120
110
 
121
111
  amqp = RuoteAMQP::Participant.new( :default_queue => 'test5' )
122
112
  @engine.register_participant( :amqp, amqp )
@@ -126,7 +116,7 @@ describe RuoteAMQP::Participant, :type => :ruote do
126
116
  @tracer.to_s.should == 'done.'
127
117
 
128
118
  begin
129
- Timeout::timeout(10) do
119
+ Timeout::timeout(5) do
130
120
  @msg = nil
131
121
  MQ.queue('test5').subscribe { |msg| @msg = msg }
132
122
 
@@ -141,9 +131,8 @@ describe RuoteAMQP::Participant, :type => :ruote do
141
131
  end
142
132
 
143
133
  it "should support mapping participant names to queue names" do
144
- pdef = <<-EOF
145
- class AmqpParticipant0 < OpenWFE::ProcessDefinition
146
134
 
135
+ pdef = ::Ruote.process_definition :name => 'test' do
147
136
  sequence do
148
137
  q1
149
138
  q2
@@ -151,7 +140,6 @@ describe RuoteAMQP::Participant, :type => :ruote do
151
140
  echo 'done.'
152
141
  end
153
142
  end
154
- EOF
155
143
 
156
144
  amqp = RuoteAMQP::Participant.new( :reply_by_default => true, :default_queue => 'test6' )
157
145
  amqp.map_participant( 'q1', 'test7' )
@@ -166,7 +154,7 @@ describe RuoteAMQP::Participant, :type => :ruote do
166
154
 
167
155
  [ 'test6', 'test7', 'test8' ].each do |q|
168
156
  begin
169
- Timeout::timeout(10) do
157
+ Timeout::timeout(5) do
170
158
  @msg = nil
171
159
  MQ.queue( q ).subscribe { |msg| @msg = msg }
172
160
 
data/spec/spec_helper.rb CHANGED
@@ -1,21 +1,34 @@
1
- begin
2
- require 'spec'
3
- rescue LoadError
4
- require 'rubygems' unless ENV['NO_RUBYGEMS']
5
- gem 'rspec'
6
- require 'spec'
7
- end
1
+ require 'rubygems'
2
+ gem 'rspec'
3
+ require 'spec'
8
4
 
9
5
  $:.unshift(File.dirname(__FILE__) + '/../lib')
6
+ $:.unshift('../ruote/lib')
7
+
8
+ # For the tests to work you need to use the AMQP gem built from
9
+ # http://github.com/kennethkalmer/amqp.git
10
+ gem 'amqp', '=0.6.6'
11
+
12
+ require 'fileutils'
13
+ require 'json'
14
+
15
+ require 'ruote/engine'
16
+ require 'ruote/worker'
17
+ require 'ruote/storage/hash_storage'
18
+ require 'ruote/log/test_logger'
19
+
10
20
  require 'ruote-amqp'
11
21
  require 'spec/ruote'
12
- require 'fileutils'
22
+
13
23
 
14
24
  # AMQP magic worked here
15
- AMQP.settings[:vhost] = '/ruote-test'
25
+ AMQP.settings[:host] = 'localhost'
26
+ AMQP.settings[:vhost] = 'ruote-test'
16
27
  AMQP.settings[:user] = 'ruote'
17
28
  AMQP.settings[:pass] = 'ruote'
18
29
 
30
+ #AMQP.logging = true
31
+
19
32
  Spec::Runner.configure do |config|
20
33
 
21
34
  config.include( RuoteSpecHelpers )
@@ -23,41 +36,20 @@ Spec::Runner.configure do |config|
23
36
  config.before(:each) do
24
37
  @tracer = Tracer.new
25
38
 
26
- ac = {}
27
-
28
- class << ac
29
- alias :old_put :[]=
30
- def []= (k, v)
31
- raise("!!!!! #{k.class}\n#{k.inspect}") \
32
- if k.class != String and k.class != Symbol
33
- old_put(k, v)
34
- end
35
- end
36
- #
37
- # useful for tracking misuses of the application context
38
-
39
- ac['__tracer'] = @tracer
40
- ac[:ruby_eval_allowed] = true
41
- ac[:definition_in_launchitem_allowed] = true
42
-
43
- @engine = OpenWFE::Engine.new( ac )
44
-
45
- @terminated_processes = []
46
- @engine.get_expression_pool.add_observer(:terminate) do |c, fe, wi|
47
- @terminated_processes << fe.fei.wfid
48
- #p [ :terminated, @terminated_processes ]
49
- end
50
-
51
- if ENV['DEBUG']
52
- $OWFE_LOG = Logger.new( STDOUT )
53
- $OWFE_LOG.level = Logger::DEBUG
54
- end
39
+ @engine = Ruote::Engine.new(
40
+ Ruote::Worker.new(
41
+ Ruote::HashStorage.new(
42
+ 's_logger' => [ 'ruote/log/test_logger', 'Ruote::TestLogger' ]
43
+ )
44
+ )
45
+ )
46
+
47
+ @engine.add_service( 'tracer', @tracer )
55
48
  end
56
49
 
57
50
  config.after(:each) do
58
- @engine.stop
59
- AMQP.stop { EM.stop }
60
- sleep 0.001 while EM.reactor_running?
51
+ @engine.shutdown
52
+ @engine.context.storage.purge!
61
53
  end
62
54
 
63
55
  config.after(:all) do