gz_activemessaging 0.13.1
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.
- checksums.yaml +15 -0
- data/.travis.yml +40 -0
- data/Appraisals +19 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +87 -0
- data/README.md +27 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/activemessaging.gemspec +137 -0
- data/gemfiles/activesupport23.gemfile +10 -0
- data/gemfiles/activesupport23.gemfile.lock +51 -0
- data/gemfiles/activesupport30.gemfile +11 -0
- data/gemfiles/activesupport30.gemfile.lock +53 -0
- data/gemfiles/activesupport31.gemfile +11 -0
- data/gemfiles/activesupport31.gemfile.lock +55 -0
- data/gemfiles/activesupport32.gemfile +10 -0
- data/gemfiles/activesupport32.gemfile.lock +55 -0
- data/generators/a13g_test_harness/a13g_test_harness_generator.rb +19 -0
- data/generators/a13g_test_harness/templates/active_messaging_test.rhtml +13 -0
- data/generators/a13g_test_harness/templates/active_messaging_test_controller.rb +29 -0
- data/generators/a13g_test_harness/templates/index.rhtml +17 -0
- data/generators/filter/USAGE +0 -0
- data/generators/filter/filter_generator.rb +19 -0
- data/generators/filter/templates/filter.rb +12 -0
- data/generators/filter/templates/filter_test.rb +28 -0
- data/generators/processor/USAGE +8 -0
- data/generators/processor/processor_generator.rb +31 -0
- data/generators/processor/templates/application_processor.rb +18 -0
- data/generators/processor/templates/broker.yml +140 -0
- data/generators/processor/templates/jruby_poller +117 -0
- data/generators/processor/templates/messaging.rb +12 -0
- data/generators/processor/templates/poller +25 -0
- data/generators/processor/templates/poller.rb +26 -0
- data/generators/processor/templates/processor.rb +8 -0
- data/generators/processor/templates/processor_test.rb +20 -0
- data/generators/tracer/USAGE +8 -0
- data/generators/tracer/templates/controller.rb +14 -0
- data/generators/tracer/templates/helper.rb +2 -0
- data/generators/tracer/templates/index.rhtml +4 -0
- data/generators/tracer/templates/layout.rhtml +16 -0
- data/generators/tracer/templates/trace_processor.rb +100 -0
- data/generators/tracer/tracer_generator.rb +25 -0
- data/init.rb +1 -0
- data/lib/activemessaging.rb +133 -0
- data/lib/activemessaging/adapter.rb +20 -0
- data/lib/activemessaging/adapters/amqp.rb +215 -0
- data/lib/activemessaging/adapters/asqs.rb +487 -0
- data/lib/activemessaging/adapters/base.rb +71 -0
- data/lib/activemessaging/adapters/beanstalk.rb +88 -0
- data/lib/activemessaging/adapters/jms.rb +243 -0
- data/lib/activemessaging/adapters/reliable_msg.rb +186 -0
- data/lib/activemessaging/adapters/stomp.rb +212 -0
- data/lib/activemessaging/adapters/synch.rb +95 -0
- data/lib/activemessaging/adapters/test.rb +137 -0
- data/lib/activemessaging/adapters/wmq.rb +193 -0
- data/lib/activemessaging/base_message.rb +28 -0
- data/lib/activemessaging/filter.rb +29 -0
- data/lib/activemessaging/gateway.rb +429 -0
- data/lib/activemessaging/message_sender.rb +30 -0
- data/lib/activemessaging/named_base.rb +54 -0
- data/lib/activemessaging/processor.rb +44 -0
- data/lib/activemessaging/railtie.rb +26 -0
- data/lib/activemessaging/test_helper.rb +189 -0
- data/lib/activemessaging/threaded_poller.rb +234 -0
- data/lib/activemessaging/trace_filter.rb +34 -0
- data/lib/generators/active_messaging/install/USAGE +21 -0
- data/lib/generators/active_messaging/install/install_generator.rb +39 -0
- data/lib/generators/active_messaging/install/templates/application_processor.rb +18 -0
- data/lib/generators/active_messaging/install/templates/broker.yml +139 -0
- data/lib/generators/active_messaging/install/templates/poller +24 -0
- data/lib/generators/active_messaging/install/templates/poller.rb +22 -0
- data/lib/generators/active_messaging/install/templates/threaded_poller +46 -0
- data/lib/generators/active_messaging/processor/USAGE +2 -0
- data/lib/generators/active_messaging/processor/processor_generator.rb +39 -0
- data/lib/generators/active_messaging/processor/templates/messaging.rb +12 -0
- data/lib/generators/active_messaging/processor/templates/processor.rb +8 -0
- data/lib/generators/active_messaging/processor/templates/processor_spec.rb +24 -0
- data/lib/generators/active_messaging/processor/templates/processor_test.rb +20 -0
- data/lib/tasks/start_consumers.rake +8 -0
- data/poller.rb +14 -0
- data/test/all_tests.rb +10 -0
- data/test/app/config/broker.yml +4 -0
- data/test/asqs_test.rb +125 -0
- data/test/config_test.rb +42 -0
- data/test/filter_test.rb +131 -0
- data/test/gateway_test.rb +220 -0
- data/test/jms_test.rb +64 -0
- data/test/reliable_msg_test.rb +83 -0
- data/test/stomp_test.rb +168 -0
- data/test/test_helper.rb +36 -0
- data/test/tracer_test.rb +57 -0
- metadata +202 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module ActiveMessaging
|
4
|
+
|
5
|
+
# This is a module so that we can send messages from (for example) web page controllers, or can receive a single message
|
6
|
+
module MessageSender
|
7
|
+
|
8
|
+
def self.included(included_by)
|
9
|
+
class << included_by
|
10
|
+
def publishes_to destination_name
|
11
|
+
ActiveMessaging::Gateway.find_destination(destination_name)
|
12
|
+
end
|
13
|
+
|
14
|
+
def receives_from destination_name
|
15
|
+
ActiveMessaging::Gateway.find_destination(destination_name)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def publish destination_name, message, headers={}, timeout=10
|
21
|
+
ActiveMessaging::Gateway.publish(destination_name, message, self.class, headers, timeout)
|
22
|
+
end
|
23
|
+
|
24
|
+
def receive destination_name, headers={}, timeout=10
|
25
|
+
ActiveMessaging::Gateway.receive(destination_name, self.class, headers, timeout)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
#Adapter to rubigen / rails
|
2
|
+
|
3
|
+
if defined?(Rails)
|
4
|
+
class NamedBase < Rails::Generator::NamedBase
|
5
|
+
end
|
6
|
+
else
|
7
|
+
class NamedBase < RubiGen::Base
|
8
|
+
attr_reader :name, :class_name, :singular_name, :plural_name
|
9
|
+
attr_reader :class_path, :file_path, :class_nesting, :class_nesting_depth
|
10
|
+
alias_method :file_name, :singular_name
|
11
|
+
alias_method :actions, :args
|
12
|
+
|
13
|
+
def initialize(runtime_args, runtime_options={})
|
14
|
+
super
|
15
|
+
|
16
|
+
base_name = self.args.first
|
17
|
+
assign_names!(base_name)
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
|
22
|
+
def assign_names!(name)
|
23
|
+
@name = name
|
24
|
+
base_name, @class_path, @file_path, @class_nesting, @class_nesting_depth = extract_modules(@name)
|
25
|
+
@class_name_without_nesting, @singular_name, @plural_name = inflect_names(base_name)
|
26
|
+
if @class_nesting.empty?
|
27
|
+
@class_name = @class_name_without_nesting
|
28
|
+
else
|
29
|
+
@table_name = @class_nesting.underscore << "_" << @table_name
|
30
|
+
@class_name = "#{@class_nesting}::#{@class_name_without_nesting}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Extract modules from filesystem-style or ruby-style path:
|
35
|
+
# good/fun/stuff
|
36
|
+
# Good::Fun::Stuff
|
37
|
+
# produce the same results.
|
38
|
+
def extract_modules(name)
|
39
|
+
modules = name.include?('/') ? name.split('/') : name.split('::')
|
40
|
+
name = modules.pop
|
41
|
+
path = modules.map { |m| m.underscore }
|
42
|
+
file_path = (path + [name.underscore]).join('/')
|
43
|
+
nesting = modules.map { |m| m.camelize }.join('::')
|
44
|
+
[name, path, file_path, nesting, modules.size]
|
45
|
+
end
|
46
|
+
|
47
|
+
def inflect_names(name)
|
48
|
+
camel = name.camelize
|
49
|
+
under = camel.underscore
|
50
|
+
plural = under.pluralize
|
51
|
+
[camel, under, plural]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# 'abstract' base class for ActiveMessaging processor classes
|
2
|
+
module ActiveMessaging
|
3
|
+
|
4
|
+
class Processor
|
5
|
+
include MessageSender
|
6
|
+
|
7
|
+
attr_reader :message
|
8
|
+
|
9
|
+
class<<self
|
10
|
+
def subscribes_to destination_name, headers={}
|
11
|
+
ActiveMessaging::Gateway.subscribe_to destination_name, self, headers
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def logger()
|
16
|
+
@@logger ||= ActiveMessaging.logger
|
17
|
+
end
|
18
|
+
|
19
|
+
def on_message(message)
|
20
|
+
raise NotImplementedError.new("Implement the on_message method in your own processor class that extends ActiveMessaging::Processor")
|
21
|
+
end
|
22
|
+
|
23
|
+
def on_error(exception)
|
24
|
+
raise exception
|
25
|
+
end
|
26
|
+
|
27
|
+
# Bind the processor to the current message so that the processor could
|
28
|
+
# potentially access headers and other attributes of the message
|
29
|
+
def process!(message)
|
30
|
+
@message = message
|
31
|
+
return on_message(message.body)
|
32
|
+
rescue Object=>err
|
33
|
+
begin
|
34
|
+
on_error(err)
|
35
|
+
rescue ActiveMessaging::AbortMessageException => rpe
|
36
|
+
logger.error "Processor:process! - AbortMessageException caught."
|
37
|
+
raise rpe
|
38
|
+
rescue Object=>ex
|
39
|
+
logger.error "Processor:process! - error in on_error, will propagate no further: #{ex.message}\n\t#{ex.backtrace.join("\n\t")}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'rails'
|
3
|
+
require 'activemessaging'
|
4
|
+
|
5
|
+
module ActiveMessaging
|
6
|
+
class Railtie < Rails::Railtie
|
7
|
+
|
8
|
+
initializer 'activemessaging.initialize' do
|
9
|
+
|
10
|
+
ActiveMessaging.load_activemessaging
|
11
|
+
|
12
|
+
if defined? Rails
|
13
|
+
ActiveMessaging.logger.info "ActiveMessaging: Rails available: Adding dispatcher prepare callback."
|
14
|
+
ActionDispatch::Callbacks.to_prepare do
|
15
|
+
ActiveMessaging.reload_activemessaging
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
rake_tasks do
|
22
|
+
load "tasks/start_consumers.rake"
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,189 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
#require "#{File.dirname(__FILE__)}/trace_filter"
|
3
|
+
|
4
|
+
|
5
|
+
module ActiveMessaging #:nodoc:
|
6
|
+
@@logger = nil
|
7
|
+
|
8
|
+
# def self.reload_activemessaging
|
9
|
+
# end
|
10
|
+
|
11
|
+
def self.logger
|
12
|
+
@@logger ||= MockLogger.new
|
13
|
+
@@logger
|
14
|
+
end
|
15
|
+
|
16
|
+
class AbortMessageException < Exception #:nodoc:
|
17
|
+
end
|
18
|
+
|
19
|
+
class StopFilterException < Exception #:nodoc:
|
20
|
+
end
|
21
|
+
|
22
|
+
class Gateway
|
23
|
+
|
24
|
+
def self.reset
|
25
|
+
unsubscribe
|
26
|
+
disconnect
|
27
|
+
@filters = []
|
28
|
+
@subscriptions = {}
|
29
|
+
@named_destinations = {}
|
30
|
+
@processor_groups = {}
|
31
|
+
@current_processor_group = nil
|
32
|
+
@connections = {}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module MessageSender
|
37
|
+
|
38
|
+
@@__a13g_initialized__ = false
|
39
|
+
def publish_with_reset(destination_name, message, headers={}, timeout=10)
|
40
|
+
unless @@__a13g_initialized__
|
41
|
+
ActiveMessaging.reload_activemessaging
|
42
|
+
@@__a13g_initialized__ = true
|
43
|
+
end
|
44
|
+
publish_without_reset(destination_name, message, headers, timeout)
|
45
|
+
end
|
46
|
+
|
47
|
+
alias_method_chain :publish, :reset
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
class TestMessage < ActiveMessaging::BaseMessage
|
52
|
+
|
53
|
+
def initialize(body="", headers={}, destination="")
|
54
|
+
super(body, nil, headers, destination)
|
55
|
+
@headers['destination'] = destination
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
module TestHelper
|
61
|
+
|
62
|
+
# #Many thanks must go to the ActiveRecord fixture code
|
63
|
+
# #for showing how to properly alias setup and teardown
|
64
|
+
# def self.included(base)
|
65
|
+
# base.extend(ClassMethods)
|
66
|
+
#
|
67
|
+
# class << base
|
68
|
+
# alias_method_chain :method_added, :a13g
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# end
|
72
|
+
|
73
|
+
# module ClassMethods
|
74
|
+
#
|
75
|
+
# def method_added_with_a13g(method)
|
76
|
+
# return if @__a13g_disable_method_added__
|
77
|
+
# @__a13g_disable_method_added__ = true
|
78
|
+
#
|
79
|
+
# case method.to_s
|
80
|
+
# when 'setup'
|
81
|
+
# unless method_defined?(:setup_without_a13g)
|
82
|
+
# alias_method :setup_without_a13g, :setup
|
83
|
+
# define_method(:full_setup) do
|
84
|
+
# setup_with_a13g
|
85
|
+
# setup_without_a13g
|
86
|
+
# end
|
87
|
+
# end
|
88
|
+
# alias_method :setup, :full_setup
|
89
|
+
# when 'teardown'
|
90
|
+
# unless method_defined?(:teardown_without_a13g)
|
91
|
+
# alias_method :teardown_without_a13g, :teardown
|
92
|
+
# define_method(:full_teardown) do
|
93
|
+
# teardown_without_a13g
|
94
|
+
# teardown_with_a13g
|
95
|
+
# end
|
96
|
+
# end
|
97
|
+
# alias_method :teardown, :full_teardown
|
98
|
+
# end
|
99
|
+
#
|
100
|
+
# method_added_without_a13g(method)
|
101
|
+
#
|
102
|
+
# @__a13g_disable_method_added__ = false
|
103
|
+
# end
|
104
|
+
#
|
105
|
+
# end
|
106
|
+
|
107
|
+
# def setup_with_a13g
|
108
|
+
# ActiveMessaging.reload_activemessaging
|
109
|
+
# end
|
110
|
+
#
|
111
|
+
# def teardown_with_a13g
|
112
|
+
# ActiveMessaging::Gateway.reset
|
113
|
+
# end
|
114
|
+
|
115
|
+
def mock_publish destination, body, publisher=nil, headers={}
|
116
|
+
ActiveMessaging::Gateway.publish destination, body, publisher, headers
|
117
|
+
end
|
118
|
+
|
119
|
+
def assert_message destination, body
|
120
|
+
destination = ActiveMessaging::Gateway.find_destination(destination).value
|
121
|
+
error_message = <<-EOF
|
122
|
+
Message for '#{destination}' with '#{body}' is not present.
|
123
|
+
Messages:
|
124
|
+
#{ActiveMessaging::Gateway.connection('default').all_messages.inspect}
|
125
|
+
EOF
|
126
|
+
assert ActiveMessaging::Gateway.connection.find_message(destination, body), error_message
|
127
|
+
end
|
128
|
+
|
129
|
+
def assert_no_message_with destination, body
|
130
|
+
destination = ActiveMessaging::Gateway.find_destination(destination).value
|
131
|
+
error_message = <<-EOF
|
132
|
+
Message for '#{destination}' with '#{body}' is present.
|
133
|
+
Messages:
|
134
|
+
#{ActiveMessaging::Gateway.connection('default').all_messages.inspect}
|
135
|
+
EOF
|
136
|
+
assert_nil ActiveMessaging::Gateway.connection('default').find_message(destination, body), error_message
|
137
|
+
end
|
138
|
+
|
139
|
+
def assert_no_messages destination
|
140
|
+
destination = ActiveMessaging::Gateway.find_destination(destination).value
|
141
|
+
error_message = <<-EOF
|
142
|
+
Expected no messages.
|
143
|
+
Messages:
|
144
|
+
#{ActiveMessaging::Gateway.connection('default').all_messages.inspect}
|
145
|
+
EOF
|
146
|
+
assert_equal [], ActiveMessaging::Gateway.connection('default').all_messages, error_message
|
147
|
+
end
|
148
|
+
|
149
|
+
def assert_subscribed destination
|
150
|
+
destination = ActiveMessaging::Gateway.find_destination(destination).value
|
151
|
+
error_message = <<-EOF
|
152
|
+
Not subscribed to #{destination}.
|
153
|
+
Subscriptions:
|
154
|
+
#{ActiveMessaging::Gateway.connection('default').subscriptions.inspect}
|
155
|
+
EOF
|
156
|
+
assert ActiveMessaging::Gateway.connection('default').find_subscription(destination), error_message
|
157
|
+
end
|
158
|
+
|
159
|
+
def assert_not_subscribed destination
|
160
|
+
destination = ActiveMessaging::Gateway.find_destination(destination).value
|
161
|
+
error_message = <<-EOF
|
162
|
+
Subscribed to #{destination}.
|
163
|
+
Subscriptions:
|
164
|
+
#{ActiveMessaging::Gateway.connection('default').subscriptions.inspect}
|
165
|
+
EOF
|
166
|
+
assert_nil ActiveMessaging::Gateway.connection('default').find_subscription(destination), error_message
|
167
|
+
end
|
168
|
+
|
169
|
+
def assert_has_messages destination
|
170
|
+
destination_name = ActiveMessaging::Gateway.find_destination(destination).value
|
171
|
+
error_message = <<-EOF
|
172
|
+
No messages for #{destination_name}.
|
173
|
+
All messages:
|
174
|
+
#{ActiveMessaging::Gateway.connection('default').all_messages.inspect}
|
175
|
+
EOF
|
176
|
+
destination = ActiveMessaging::Gateway.connection('default').find_destination destination_name
|
177
|
+
assert !destination.nil? && !destination.messages.empty?, error_message
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
class MockLogger
|
182
|
+
def error(*args) ; end
|
183
|
+
def warn(*args) ; end
|
184
|
+
def info(*args) ; end
|
185
|
+
def debug(*args) ; end
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|
189
|
+
|
@@ -0,0 +1,234 @@
|
|
1
|
+
# This owes no small debt to sidekiq for showing how to use celluloid for polling for messages.
|
2
|
+
# https://github.com/mperham/sidekiq/blob/poller/lib/sidekiq/manager.rb
|
3
|
+
if RUBY_VERSION.to_f >= 1.9 # Celluloid requires fibers support, which is not available on 1.8
|
4
|
+
require 'celluloid'
|
5
|
+
|
6
|
+
module ActiveMessaging
|
7
|
+
|
8
|
+
class ThreadedPoller
|
9
|
+
|
10
|
+
include Celluloid
|
11
|
+
|
12
|
+
# traps when any worker dies
|
13
|
+
trap_exit :died
|
14
|
+
|
15
|
+
attr_accessor :configuration, :receiver, :connection, :workers, :busy, :running, :pause
|
16
|
+
|
17
|
+
#
|
18
|
+
# connection is a string, name of the connection from broker.yml to use for this threaded poller instance
|
19
|
+
#
|
20
|
+
# configuration is a list of hashes
|
21
|
+
# each has describes a group of worker threads
|
22
|
+
# for each group, define what priorities those workers will process
|
23
|
+
# [
|
24
|
+
# {
|
25
|
+
# :pool_size => 1 # number of workers of this type
|
26
|
+
# :priorities => [1,2,3] # what message priorities this thread will process
|
27
|
+
# }
|
28
|
+
# ]
|
29
|
+
#
|
30
|
+
def initialize(connection='default', configuration={})
|
31
|
+
# default config is a pool size of 3 worker threads
|
32
|
+
self.configuration = configuration || [{:pool_size => 3}]
|
33
|
+
self.connection = connection
|
34
|
+
self.pause = 1
|
35
|
+
end
|
36
|
+
|
37
|
+
def start
|
38
|
+
logger.info "ActiveMessaging::ThreadedPoller start"
|
39
|
+
|
40
|
+
# these are workers ready to use
|
41
|
+
self.workers = []
|
42
|
+
|
43
|
+
# these are workers already working
|
44
|
+
self.busy = []
|
45
|
+
|
46
|
+
# this indicates if we are running or not, helps threads to stop gracefully
|
47
|
+
self.running = true
|
48
|
+
|
49
|
+
# subscribe will create the connections based on subscriptions in processsors
|
50
|
+
# (you can't find or use the connection until it is created by calling this)
|
51
|
+
ActiveMessaging::Gateway.subscribe
|
52
|
+
|
53
|
+
# create a message receiver actor, ony need one, using connection
|
54
|
+
receiver_connection = ActiveMessaging::Gateway.connection(connection)
|
55
|
+
self.receiver = MessageReceiver.new(current_actor, receiver_connection, pause)
|
56
|
+
|
57
|
+
# start the workers based on the config
|
58
|
+
configuration.each do |c|
|
59
|
+
(c[:pool_size] || 1).times{ self.workers << Worker.new_link(current_actor, c) }
|
60
|
+
end
|
61
|
+
|
62
|
+
# once all workers are created, start them up
|
63
|
+
self.workers.each{|worker| receive(worker)}
|
64
|
+
|
65
|
+
# in debug level, log info about workers every 10 seconds
|
66
|
+
log_status
|
67
|
+
end
|
68
|
+
|
69
|
+
def stop
|
70
|
+
logger.info "ActiveMessaging::ThreadedPoller stop"
|
71
|
+
# indicates to all busy workers not to pick up another messages, but does not interrupt
|
72
|
+
# also indicates to the message receiver to stop getting more messages
|
73
|
+
self.running = false
|
74
|
+
|
75
|
+
# tell each waiting worker to shut down. Running ones will be allowed to finish
|
76
|
+
receiver.terminate! if receiver.alive?
|
77
|
+
logger.info "ActiveMessaging::ThreadedPoller receiver terminated"
|
78
|
+
|
79
|
+
workers.each { |w| w.terminate! if w.alive? }
|
80
|
+
logger.info "ActiveMessaging::ThreadedPoller workers terminated"
|
81
|
+
|
82
|
+
|
83
|
+
after(0) { signal(:shutdown) } if stopped?
|
84
|
+
end
|
85
|
+
|
86
|
+
# recursive method, uses celluloid 'after' to keep calling
|
87
|
+
def log_status
|
88
|
+
return unless logger.debug?
|
89
|
+
logger.debug("ActiveMessaging::ThreadedPoller: conn:#{connection}, #{workers.count}, #{busy.count}, #{running}")
|
90
|
+
after(10){ log_status }
|
91
|
+
end
|
92
|
+
|
93
|
+
def receive(worker)
|
94
|
+
receiver.receive!(worker) if (receiver && running && worker)
|
95
|
+
end
|
96
|
+
|
97
|
+
def dispatch(message, worker)
|
98
|
+
workers.delete(worker)
|
99
|
+
busy << worker
|
100
|
+
worker.execute!(message)
|
101
|
+
end
|
102
|
+
|
103
|
+
def executed(worker)
|
104
|
+
busy.delete(worker)
|
105
|
+
|
106
|
+
if running
|
107
|
+
workers << worker
|
108
|
+
receive(worker)
|
109
|
+
else
|
110
|
+
worker.terminate if worker.alive?
|
111
|
+
if busy.empty?
|
112
|
+
logger.info "all executed: signal stopped"
|
113
|
+
after(0) { signal(:shutdown) }
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def died(worker, reason)
|
119
|
+
busy.delete(worker)
|
120
|
+
|
121
|
+
if running
|
122
|
+
logger.info "uh oh, #{worker.inspect} died because of #{reason.class}"
|
123
|
+
worker = Worker.new_link(current_actor)
|
124
|
+
workers << worker
|
125
|
+
receive(worker)
|
126
|
+
else
|
127
|
+
logger.info "check to see if busy is empty: #{busy.inspect}"
|
128
|
+
if busy.empty?
|
129
|
+
logger.info "all died: signal stopped"
|
130
|
+
after(0){ signal(:shutdown) }
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def stopped?
|
136
|
+
(!running && busy.empty?)
|
137
|
+
end
|
138
|
+
|
139
|
+
def inspect
|
140
|
+
"#<ThreadedPoller #{to_s}>"
|
141
|
+
end
|
142
|
+
|
143
|
+
def to_s
|
144
|
+
@str ||= "#{Process.pid}-#{Thread.current.object_id}:#{self.object_id}"
|
145
|
+
end
|
146
|
+
|
147
|
+
def logger; ActiveMessaging.logger; end
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
class MessageReceiver
|
152
|
+
include Celluloid
|
153
|
+
|
154
|
+
attr_accessor :poller, :connection, :pause
|
155
|
+
|
156
|
+
def initialize(poller, connection, pause=1)
|
157
|
+
logger.debug("MessageReceiver initialize: poller:#{poller}, connection:#{connection}, pause:#{pause}")
|
158
|
+
|
159
|
+
raise "No connection found for '#{poller.connection}'" unless connection
|
160
|
+
|
161
|
+
self.poller = poller
|
162
|
+
self.connection = connection
|
163
|
+
self.pause = pause
|
164
|
+
end
|
165
|
+
|
166
|
+
def receive(worker)
|
167
|
+
return unless poller.running
|
168
|
+
|
169
|
+
# logger.debug("***** MessageReceiver calling receive")
|
170
|
+
message = self.connection.receive(worker.options)
|
171
|
+
# logger.debug("***** MessageReceiver receive returned")
|
172
|
+
|
173
|
+
if message
|
174
|
+
logger.debug("ActiveMessaging::MessageReceiver.receive: message:'#{message.inspect}'")
|
175
|
+
poller.dispatch!(message, worker)
|
176
|
+
else
|
177
|
+
if (!poller || !poller.alive? || !poller.running)
|
178
|
+
logger.debug("ActiveMessaging::MessageReceiver.receive: terminate")
|
179
|
+
self.terminate
|
180
|
+
end
|
181
|
+
logger.debug("ActiveMessaging::MessageReceiver.receive: no message for worker #{worker.object_id}, retry in #{pause} sec")
|
182
|
+
after(pause) { receive(worker) }
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|
186
|
+
|
187
|
+
def inspect
|
188
|
+
"#<MessageReceiver #{to_s}>"
|
189
|
+
end
|
190
|
+
|
191
|
+
def to_s
|
192
|
+
@str ||= "#{Process.pid}-#{Thread.current.object_id}:#{self.object_id}"
|
193
|
+
end
|
194
|
+
|
195
|
+
def logger; ::ActiveMessaging.logger; end
|
196
|
+
end
|
197
|
+
|
198
|
+
class Worker
|
199
|
+
include Celluloid
|
200
|
+
|
201
|
+
attr_accessor :poller, :options
|
202
|
+
|
203
|
+
def initialize(poller, options)
|
204
|
+
self.poller = poller
|
205
|
+
self.options = options
|
206
|
+
end
|
207
|
+
|
208
|
+
def execute(message)
|
209
|
+
begin
|
210
|
+
::ActiveMessaging::Gateway.dispatch(message)
|
211
|
+
rescue Object => err
|
212
|
+
logger.error("ActiveMessaging::Worker.execute error - #{err.inspect}")
|
213
|
+
abort(err)
|
214
|
+
ensure
|
215
|
+
::ActiveRecord::Base.clear_active_connections! if defined?(::ActiveRecord)
|
216
|
+
end
|
217
|
+
|
218
|
+
poller.executed!(current_actor)
|
219
|
+
end
|
220
|
+
|
221
|
+
def inspect
|
222
|
+
"#<Worker #{to_s}>"
|
223
|
+
end
|
224
|
+
|
225
|
+
def to_s
|
226
|
+
@str ||= "#{Process.pid}-#{Thread.current.object_id}:#{self.object_id}"
|
227
|
+
end
|
228
|
+
|
229
|
+
def logger; ::ActiveMessaging.logger; end
|
230
|
+
|
231
|
+
end
|
232
|
+
|
233
|
+
end
|
234
|
+
end # if RUBY_VERSION
|