action_subscriber 2.5.0.pre2 → 3.0.0.pre1
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 +4 -4
- data/action_subscriber.gemspec +1 -0
- data/lib/action_subscriber/babou.rb +2 -29
- data/lib/action_subscriber/base.rb +0 -4
- data/lib/action_subscriber/bunny/subscriber.rb +14 -4
- data/lib/action_subscriber/configuration.rb +1 -11
- data/lib/action_subscriber/default_routing.rb +6 -4
- data/lib/action_subscriber/march_hare/subscriber.rb +14 -4
- data/lib/action_subscriber/message_retry.rb +1 -1
- data/lib/action_subscriber/middleware/env.rb +3 -1
- data/lib/action_subscriber/middleware/error_handler.rb +11 -4
- data/lib/action_subscriber/rabbit_connection.rb +23 -34
- data/lib/action_subscriber/route.rb +5 -1
- data/lib/action_subscriber/route_set.rb +12 -11
- data/lib/action_subscriber/router.rb +13 -2
- data/lib/action_subscriber/version.rb +1 -1
- data/lib/action_subscriber.rb +11 -24
- data/spec/integration/around_filters_spec.rb +1 -1
- data/spec/integration/at_least_once_spec.rb +1 -1
- data/spec/integration/at_most_once_spec.rb +1 -1
- data/spec/integration/automatic_reconnect_spec.rb +3 -4
- data/spec/integration/basic_subscriber_spec.rb +2 -2
- data/spec/integration/custom_actions_spec.rb +1 -1
- data/spec/integration/custom_headers_spec.rb +2 -2
- data/spec/integration/decoding_payloads_spec.rb +2 -2
- data/spec/integration/manual_acknowledgement_spec.rb +1 -1
- data/spec/integration/multiple_connections_spec.rb +36 -0
- data/spec/integration/multiple_threadpools_spec.rb +3 -3
- data/spec/lib/action_subscriber/configuration_spec.rb +1 -5
- data/spec/spec_helper.rb +7 -4
- metadata +18 -14
- data/lib/action_subscriber/publisher/async/in_memory_adapter.rb +0 -153
- data/lib/action_subscriber/publisher/async.rb +0 -31
- data/lib/action_subscriber/publisher.rb +0 -46
- data/lib/action_subscriber/synchronizer.rb +0 -15
- data/spec/integration/inferred_routes_spec.rb +0 -53
- data/spec/lib/action_subscriber/publisher/async/in_memory_adapter_spec.rb +0 -135
- data/spec/lib/action_subscriber/publisher/async_spec.rb +0 -40
- data/spec/lib/action_subscriber/publisher_spec.rb +0 -35
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b0a848297f91f557f43e6240545866aaad495d17
|
4
|
+
data.tar.gz: 0fd512e453740a0ad0e34f1f42ddef7ab5ac240f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d30b59daffa7e89a4c48eb3044a65af90804d91b3c0991e3dd0899b9a20944532878bc6327684577d05c11b9017edfb233bbd251daa42dff9a50d614f4701da
|
7
|
+
data.tar.gz: df4cf38fe9cbfed26adcc53e43823348726176cc387ccaa46d22274099182198aa1c2d1fcd1c7e341d87dd6e4f1a88e24702788a41c9955e8a2161a880459d56
|
data/action_subscriber.gemspec
CHANGED
@@ -30,6 +30,7 @@ Gem::Specification.new do |spec|
|
|
30
30
|
spec.add_dependency 'middleware'
|
31
31
|
spec.add_dependency 'thor'
|
32
32
|
|
33
|
+
spec.add_development_dependency "active_publisher", "~> 0.1.5"
|
33
34
|
spec.add_development_dependency "activerecord", ">= 3.2"
|
34
35
|
spec.add_development_dependency "bundler", ">= 1.6"
|
35
36
|
spec.add_development_dependency "pry-nav"
|
@@ -7,7 +7,7 @@ module ActionSubscriber
|
|
7
7
|
def self.auto_pop!
|
8
8
|
@pop_mode = true
|
9
9
|
reload_active_record
|
10
|
-
|
10
|
+
::ActionSubscriber.setup_default_connection!
|
11
11
|
sleep_time = ::ActionSubscriber.configuration.pop_interval.to_i / 1000.0
|
12
12
|
|
13
13
|
::ActionSubscriber.start_queues
|
@@ -30,7 +30,7 @@ module ActionSubscriber
|
|
30
30
|
def self.start_subscribers
|
31
31
|
@prowl_mode = true
|
32
32
|
reload_active_record
|
33
|
-
|
33
|
+
::ActionSubscriber.setup_default_connection!
|
34
34
|
|
35
35
|
::ActionSubscriber.start_subscribers
|
36
36
|
logger.info "Action Subscriber connected"
|
@@ -45,29 +45,6 @@ module ActionSubscriber
|
|
45
45
|
!!@prowl_mode
|
46
46
|
end
|
47
47
|
|
48
|
-
def self.load_subscribers
|
49
|
-
subscription_paths = ["subscriptions", "subscribers"]
|
50
|
-
path_prefixes = ["lib", "app"]
|
51
|
-
cloned_paths = subscription_paths.dup
|
52
|
-
|
53
|
-
path_prefixes.each do |prefix|
|
54
|
-
cloned_paths.each { |path| subscription_paths << "#{prefix}/#{path}" }
|
55
|
-
end
|
56
|
-
|
57
|
-
absolute_subscription_paths = subscription_paths.map{ |path| ::File.expand_path(path) }
|
58
|
-
absolute_subscription_paths.each do |path|
|
59
|
-
if ::File.exists?("#{path}.rb")
|
60
|
-
load("#{path}.rb")
|
61
|
-
end
|
62
|
-
|
63
|
-
if ::File.directory?(path)
|
64
|
-
::Dir[::File.join(path, "**", "*.rb")].sort.each do |file|
|
65
|
-
load file
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
48
|
def self.logger
|
72
49
|
::ActionSubscriber::Logging.logger
|
73
50
|
end
|
@@ -108,9 +85,5 @@ module ActionSubscriber
|
|
108
85
|
|
109
86
|
puts "threadpool empty. Shutting down"
|
110
87
|
end
|
111
|
-
|
112
|
-
def self.subscribers_loaded?
|
113
|
-
!::ActionSubscriber::Base.inherited_classes.empty?
|
114
|
-
end
|
115
88
|
end
|
116
89
|
end
|
@@ -20,7 +20,9 @@ module ActionSubscriber
|
|
20
20
|
# of times we will pop each time we poll the broker
|
21
21
|
times_to_pop = [::ActionSubscriber::Threadpool.ready_size, ::ActionSubscriber.config.times_to_pop].min
|
22
22
|
times_to_pop.times do
|
23
|
-
|
23
|
+
subscriptions.each do |subscription|
|
24
|
+
route = subscription[:route]
|
25
|
+
queue = subscription[:queue]
|
24
26
|
# Handle busy checks on a per threadpool basis
|
25
27
|
next if route.threadpool.busy?
|
26
28
|
|
@@ -29,7 +31,6 @@ module ActionSubscriber
|
|
29
31
|
::ActiveSupport::Notifications.instrument "popped_event.action_subscriber", :payload_size => encoded_payload.bytesize, :queue => queue.name
|
30
32
|
properties = {
|
31
33
|
:action => route.action,
|
32
|
-
:channel => queue.channel,
|
33
34
|
:content_type => properties[:content_type],
|
34
35
|
:delivery_tag => delivery_info.delivery_tag,
|
35
36
|
:exchange => delivery_info.exchange,
|
@@ -45,7 +46,9 @@ module ActionSubscriber
|
|
45
46
|
end
|
46
47
|
|
47
48
|
def auto_subscribe!
|
48
|
-
|
49
|
+
subscriptions.each do |subscription|
|
50
|
+
route = subscription[:route]
|
51
|
+
queue = subscription[:queue]
|
49
52
|
channel = queue.channel
|
50
53
|
channel.prefetch(route.prefetch) if route.acknowledgements?
|
51
54
|
consumer = ::Bunny::Consumer.new(channel, queue, channel.generate_consumer_tag, !route.acknowledgements?)
|
@@ -63,7 +66,7 @@ module ActionSubscriber
|
|
63
66
|
:queue => queue.name,
|
64
67
|
}
|
65
68
|
env = ::ActionSubscriber::Middleware::Env.new(route.subscriber, encoded_payload, properties)
|
66
|
-
|
69
|
+
run_env(env)
|
67
70
|
end
|
68
71
|
bunny_consumers << consumer
|
69
72
|
queue.subscribe_with(consumer)
|
@@ -80,6 +83,13 @@ module ActionSubscriber
|
|
80
83
|
end
|
81
84
|
end
|
82
85
|
end
|
86
|
+
|
87
|
+
def run_env(env)
|
88
|
+
logger.info "RECEIVED #{env.message_id} from #{env.queue}"
|
89
|
+
::ActiveSupport::Notifications.instrument "process_event.action_subscriber", :subscriber => env.subscriber.to_s, :routing_key => env.routing_key, :queue => env.queue do
|
90
|
+
::ActionSubscriber.config.middleware.call(env)
|
91
|
+
end
|
92
|
+
end
|
83
93
|
end
|
84
94
|
end
|
85
95
|
end
|
@@ -4,10 +4,6 @@ require "action_subscriber/uri"
|
|
4
4
|
module ActionSubscriber
|
5
5
|
class Configuration
|
6
6
|
attr_accessor :allow_low_priority_methods,
|
7
|
-
:async_publisher,
|
8
|
-
:async_publisher_drop_messages_when_queue_full,
|
9
|
-
:async_publisher_max_queue_size,
|
10
|
-
:async_publisher_supervisor_interval,
|
11
7
|
:decoder,
|
12
8
|
:default_exchange,
|
13
9
|
:error_handler,
|
@@ -19,7 +15,6 @@ module ActionSubscriber
|
|
19
15
|
:pop_interval,
|
20
16
|
:port,
|
21
17
|
:prefetch,
|
22
|
-
:publisher_confirms,
|
23
18
|
:seconds_to_wait_for_graceful_shutdown,
|
24
19
|
:username,
|
25
20
|
:threadpool_size,
|
@@ -31,10 +26,6 @@ module ActionSubscriber
|
|
31
26
|
|
32
27
|
DEFAULTS = {
|
33
28
|
:allow_low_priority_methods => false,
|
34
|
-
:async_publisher => 'memory',
|
35
|
-
:async_publisher_drop_messages_when_queue_full => false,
|
36
|
-
:async_publisher_max_queue_size => 1_000_000,
|
37
|
-
:async_publisher_supervisor_interval => 200, # in milliseconds
|
38
29
|
:default_exchange => 'events',
|
39
30
|
:heartbeat => 5,
|
40
31
|
:host => 'localhost',
|
@@ -42,8 +33,7 @@ module ActionSubscriber
|
|
42
33
|
:mode => 'subscribe',
|
43
34
|
:pop_interval => 100, # in milliseconds
|
44
35
|
:port => 5672,
|
45
|
-
:prefetch =>
|
46
|
-
:publisher_confirms => false,
|
36
|
+
:prefetch => 2,
|
47
37
|
:seconds_to_wait_for_graceful_shutdown => 30,
|
48
38
|
:threadpool_size => 8,
|
49
39
|
:timeout => 1,
|
@@ -1,19 +1,21 @@
|
|
1
1
|
module ActionSubscriber
|
2
2
|
module DefaultRouting
|
3
|
-
def routes
|
3
|
+
def routes(route_settings)
|
4
4
|
@routes ||= begin
|
5
5
|
routes = []
|
6
6
|
exchange_names.each do |exchange_name|
|
7
7
|
subscribable_methods.each do |method_name|
|
8
|
-
|
8
|
+
settings = {
|
9
9
|
acknowledgements: acknowledge_messages?,
|
10
10
|
action: method_name,
|
11
|
-
durable: false,
|
11
|
+
durable: false,
|
12
12
|
exchange: exchange_name,
|
13
13
|
routing_key: routing_key_name_for_method(method_name),
|
14
14
|
subscriber: self,
|
15
15
|
queue: queue_name_for_method(method_name),
|
16
|
-
}
|
16
|
+
}
|
17
|
+
settings.merge!(route_settings)
|
18
|
+
routes << ActionSubscriber::Route.new(settings)
|
17
19
|
end
|
18
20
|
end
|
19
21
|
routes
|
@@ -18,7 +18,9 @@ module ActionSubscriber
|
|
18
18
|
# of times we will pop each time we poll the broker
|
19
19
|
times_to_pop = [::ActionSubscriber::Threadpool.ready_size, ::ActionSubscriber.config.times_to_pop].min
|
20
20
|
times_to_pop.times do
|
21
|
-
|
21
|
+
subscriptions.each do |subscription|
|
22
|
+
route = subscription[:route]
|
23
|
+
queue = subscription[:queue]
|
22
24
|
# Handle busy checks on a per threadpool basis
|
23
25
|
next if route.threadpool.busy?
|
24
26
|
|
@@ -27,7 +29,6 @@ module ActionSubscriber
|
|
27
29
|
::ActiveSupport::Notifications.instrument "popped_event.action_subscriber", :payload_size => encoded_payload.bytesize, :queue => queue.name
|
28
30
|
properties = {
|
29
31
|
:action => route.action,
|
30
|
-
:channel => queue.channel,
|
31
32
|
:content_type => metadata.content_type,
|
32
33
|
:delivery_tag => metadata.delivery_tag,
|
33
34
|
:exchange => metadata.exchange,
|
@@ -46,7 +47,9 @@ module ActionSubscriber
|
|
46
47
|
end
|
47
48
|
|
48
49
|
def auto_subscribe!
|
49
|
-
|
50
|
+
subscriptions.each do |subscription|
|
51
|
+
route = subscription[:route]
|
52
|
+
queue = subscription[:queue]
|
50
53
|
queue.channel.prefetch = route.prefetch if route.acknowledgements?
|
51
54
|
consumer = queue.subscribe(route.queue_subscription_options) do |metadata, encoded_payload|
|
52
55
|
::ActiveSupport::Notifications.instrument "received_event.action_subscriber", :payload_size => encoded_payload.bytesize, :queue => queue.name
|
@@ -62,7 +65,7 @@ module ActionSubscriber
|
|
62
65
|
:queue => queue.name,
|
63
66
|
}
|
64
67
|
env = ::ActionSubscriber::Middleware::Env.new(route.subscriber, encoded_payload, properties)
|
65
|
-
|
68
|
+
run_env(env)
|
66
69
|
end
|
67
70
|
|
68
71
|
march_hare_consumers << consumer
|
@@ -84,6 +87,13 @@ module ActionSubscriber
|
|
84
87
|
end
|
85
88
|
end
|
86
89
|
|
90
|
+
def run_env(env)
|
91
|
+
logger.info "RECEIVED #{env.message_id} from #{env.queue}"
|
92
|
+
::ActiveSupport::Notifications.instrument "process_event.action_subscriber", :subscriber => env.subscriber.to_s, :routing_key => env.routing_key, :queue => env.queue do
|
93
|
+
::ActionSubscriber.config.middleware.call(env)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
87
97
|
def _normalized_headers(metadata)
|
88
98
|
return {} unless metadata.headers
|
89
99
|
metadata.headers.each_with_object({}) do |(header,value), hash|
|
@@ -46,7 +46,7 @@ module ActionSubscriber
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def self.with_exchange(env, ttl, retry_queue_name)
|
49
|
-
channel = RabbitConnection.
|
49
|
+
channel = RabbitConnection.with_connection(:default){|connection| connection.create_channel}
|
50
50
|
begin
|
51
51
|
channel.confirm_select
|
52
52
|
# an empty string is the default exchange [see bunny docs](http://rubybunny.info/articles/exchanges.html#default_exchange)
|
@@ -28,7 +28,7 @@ module ActionSubscriber
|
|
28
28
|
# :routing_key => String
|
29
29
|
def initialize(subscriber, encoded_payload, properties)
|
30
30
|
@action = properties.fetch(:action)
|
31
|
-
@channel = properties
|
31
|
+
@channel = properties[:channel]
|
32
32
|
@content_type = properties.fetch(:content_type)
|
33
33
|
@delivery_tag = properties.fetch(:delivery_tag)
|
34
34
|
@encoded_payload = encoded_payload
|
@@ -41,12 +41,14 @@ module ActionSubscriber
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def acknowledge
|
44
|
+
fail ::RuntimeError, "you can't acknowledge messages under the polling API" unless @channel
|
44
45
|
acknowledge_multiple_messages = false
|
45
46
|
@channel.ack(@delivery_tag, acknowledge_multiple_messages)
|
46
47
|
true
|
47
48
|
end
|
48
49
|
|
49
50
|
def reject
|
51
|
+
fail ::RuntimeError, "you can't acknowledge messages under the polling API" unless @channel
|
50
52
|
requeue_message = true
|
51
53
|
@channel.reject(@delivery_tag, requeue_message)
|
52
54
|
true
|
@@ -8,10 +8,17 @@ module ActionSubscriber
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def call(env)
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
# This insulates the connection thread from errors that are raised by the error_handle or
|
12
|
+
# exceptions that don't fall under StandardError (which are not caught by `rescue => error`)
|
13
|
+
new_thread = ::Thread.new do
|
14
|
+
begin
|
15
|
+
@app.call(env)
|
16
|
+
rescue => error
|
17
|
+
logger.error "FAILED #{env.message_id}"
|
18
|
+
::ActionSubscriber.configuration.error_handler.call(error, env.to_h)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
::Thread.pass while new_thread.alive?
|
15
22
|
end
|
16
23
|
end
|
17
24
|
end
|
@@ -3,57 +3,40 @@ require 'thread'
|
|
3
3
|
module ActionSubscriber
|
4
4
|
module RabbitConnection
|
5
5
|
SUBSCRIBER_CONNECTION_MUTEX = ::Mutex.new
|
6
|
-
PUBLISHER_CONNECTION_MUTEX = ::Mutex.new
|
7
6
|
NETWORK_RECOVERY_INTERVAL = 1.freeze
|
8
7
|
|
9
|
-
def self.
|
10
|
-
publisher_connection.try(:connected?)
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.publisher_connection
|
8
|
+
def self.setup_connection(name, settings)
|
14
9
|
SUBSCRIBER_CONNECTION_MUTEX.synchronize do
|
15
|
-
|
16
|
-
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.publisher_disconnect!
|
21
|
-
SUBSCRIBER_CONNECTION_MUTEX.synchronize do
|
22
|
-
if @publisher_connection && @publisher_connection.connected?
|
23
|
-
@publisher_connection.close
|
24
|
-
end
|
25
|
-
|
26
|
-
@publisher_connection = nil
|
10
|
+
fail ArgumentError, "a #{name} connection already exists" if subscriber_connections[name]
|
11
|
+
subscriber_connections[name] = create_connection(settings)
|
27
12
|
end
|
28
13
|
end
|
29
14
|
|
30
15
|
def self.subscriber_connected?
|
31
|
-
|
16
|
+
subscriber_connections.all?{|_name, connection| connection.connected?}
|
32
17
|
end
|
33
18
|
|
34
|
-
def self.
|
19
|
+
def self.subscriber_disconnect!
|
35
20
|
SUBSCRIBER_CONNECTION_MUTEX.synchronize do
|
36
|
-
|
37
|
-
@
|
21
|
+
subscriber_connections.each{|_name, connection| connection.close}
|
22
|
+
@subscriber_connections = []
|
38
23
|
end
|
39
24
|
end
|
40
25
|
|
41
|
-
def self.
|
26
|
+
def self.with_connection(name)
|
42
27
|
SUBSCRIBER_CONNECTION_MUTEX.synchronize do
|
43
|
-
|
44
|
-
|
45
|
-
end
|
46
|
-
|
47
|
-
@subscriber_connection = nil
|
28
|
+
fail ArgumentError, "there is no connection named #{name}" unless subscriber_connections[name]
|
29
|
+
yield(subscriber_connections[name])
|
48
30
|
end
|
49
31
|
end
|
50
32
|
|
51
33
|
# Private API
|
52
|
-
def self.create_connection
|
34
|
+
def self.create_connection(settings)
|
35
|
+
options = connection_options.merge(settings)
|
53
36
|
if ::RUBY_PLATFORM == "java"
|
54
|
-
connection = ::MarchHare.connect(
|
37
|
+
connection = ::MarchHare.connect(options)
|
55
38
|
else
|
56
|
-
connection = ::Bunny.new(
|
39
|
+
connection = ::Bunny.new(options)
|
57
40
|
connection.start
|
58
41
|
connection
|
59
42
|
end
|
@@ -62,18 +45,24 @@ module ActionSubscriber
|
|
62
45
|
|
63
46
|
def self.connection_options
|
64
47
|
{
|
48
|
+
:automatically_recover => true,
|
65
49
|
:continuation_timeout => ::ActionSubscriber.configuration.timeout * 1_000.0, #convert sec to ms
|
66
50
|
:heartbeat => ::ActionSubscriber.configuration.heartbeat,
|
67
51
|
:hosts => ::ActionSubscriber.configuration.hosts,
|
52
|
+
:network_recovery_interval => NETWORK_RECOVERY_INTERVAL,
|
68
53
|
:pass => ::ActionSubscriber.configuration.password,
|
69
54
|
:port => ::ActionSubscriber.configuration.port,
|
55
|
+
:recover_from_connection_close => true,
|
56
|
+
:threadpool_size => ::ActionSubscriber.configuration.threadpool_size,
|
70
57
|
:user => ::ActionSubscriber.configuration.username,
|
71
58
|
:vhost => ::ActionSubscriber.configuration.virtual_host,
|
72
|
-
:automatically_recover => true,
|
73
|
-
:network_recovery_interval => NETWORK_RECOVERY_INTERVAL,
|
74
|
-
:recover_from_connection_close => true,
|
75
59
|
}
|
76
60
|
end
|
77
61
|
private_class_method :connection_options
|
62
|
+
|
63
|
+
def self.subscriber_connections
|
64
|
+
@subscriber_connections ||= {}
|
65
|
+
end
|
66
|
+
private_class_method :subscriber_connections
|
78
67
|
end
|
79
68
|
end
|
@@ -2,7 +2,9 @@ module ActionSubscriber
|
|
2
2
|
class Route
|
3
3
|
attr_reader :acknowledgements,
|
4
4
|
:action,
|
5
|
-
:
|
5
|
+
:concurrency,
|
6
|
+
:connection_name,
|
7
|
+
:durable,
|
6
8
|
:exchange,
|
7
9
|
:prefetch,
|
8
10
|
:queue,
|
@@ -13,6 +15,8 @@ module ActionSubscriber
|
|
13
15
|
def initialize(attributes)
|
14
16
|
@acknowledgements = attributes.fetch(:acknowledgements)
|
15
17
|
@action = attributes.fetch(:action)
|
18
|
+
@concurrency = attributes.fetch(:concurrency, 1)
|
19
|
+
@connection_name = attributes.fetch(:connection_name)
|
16
20
|
@durable = attributes.fetch(:durable)
|
17
21
|
@exchange = attributes.fetch(:exchange).to_s
|
18
22
|
@prefetch = attributes.fetch(:prefetch) { ::ActionSubscriber.config.prefetch }
|
@@ -12,27 +12,28 @@ module ActionSubscriber
|
|
12
12
|
@routes = routes
|
13
13
|
end
|
14
14
|
|
15
|
-
def
|
15
|
+
def setup_subscriptions!
|
16
|
+
fail ::RuntimeError, "you cannot setup queues multiple times, this should only happen once at startup" unless subscriptions.empty?
|
16
17
|
routes.each do |route|
|
17
|
-
|
18
|
+
route.concurrency.times do
|
19
|
+
subscriptions << {
|
20
|
+
:route => route,
|
21
|
+
:queue => setup_queue(route),
|
22
|
+
}
|
23
|
+
end
|
18
24
|
end
|
19
25
|
end
|
20
26
|
|
21
27
|
private
|
22
28
|
|
23
|
-
def
|
24
|
-
@
|
29
|
+
def subscriptions
|
30
|
+
@subscriptions ||= []
|
25
31
|
end
|
26
32
|
|
27
33
|
def setup_queue(route)
|
28
|
-
channel = ::ActionSubscriber::RabbitConnection.
|
29
|
-
# Make channels threadsafe again! Believe Me!
|
30
|
-
# Accessing channels from multiple threads for messsage acknowledgement will crash
|
31
|
-
# a channel and stop messages from being received on that channel
|
32
|
-
# this isn't very clear in the documentation for march_hare/bunny, but it is
|
33
|
-
# explicitly addresses here: https://github.com/rabbitmq/rabbitmq-java-client/issues/53
|
34
|
-
channel = ::ActionSubscriber::Synchronizer.new(channel)
|
34
|
+
channel = ::ActionSubscriber::RabbitConnection.with_connection(route.connection_name){ |connection| connection.create_channel }
|
35
35
|
exchange = channel.topic(route.exchange)
|
36
|
+
# TODO go to back to the old way of creating a queue?
|
36
37
|
queue = create_queue(channel, route.queue, :durable => route.durable)
|
37
38
|
queue.bind(exchange, :routing_key => route.routing_key)
|
38
39
|
queue
|
@@ -12,6 +12,17 @@ module ActionSubscriber
|
|
12
12
|
:exchange => "events",
|
13
13
|
}.freeze
|
14
14
|
|
15
|
+
def initialize
|
16
|
+
@current_connection_name = :default
|
17
|
+
end
|
18
|
+
|
19
|
+
def connection(name, settings)
|
20
|
+
::ActionSubscriber::RabbitConnection.setup_connection(name, settings)
|
21
|
+
@current_connection_name = name
|
22
|
+
yield
|
23
|
+
@current_connection_name = :default
|
24
|
+
end
|
25
|
+
|
15
26
|
def default_routing_key_for(route_settings)
|
16
27
|
[
|
17
28
|
route_settings[:publisher],
|
@@ -30,7 +41,7 @@ module ActionSubscriber
|
|
30
41
|
end
|
31
42
|
|
32
43
|
def default_routes_for(subscriber)
|
33
|
-
subscriber.routes.each do |route|
|
44
|
+
subscriber.routes({:connection_name => @current_connection_name}).each do |route|
|
34
45
|
routes << route
|
35
46
|
end
|
36
47
|
end
|
@@ -40,7 +51,7 @@ module ActionSubscriber
|
|
40
51
|
end
|
41
52
|
|
42
53
|
def route(subscriber, action, options = {})
|
43
|
-
route_settings = DEFAULT_SETTINGS.merge(options).merge(:subscriber => subscriber, :action => action)
|
54
|
+
route_settings = DEFAULT_SETTINGS.merge(:connection_name => @current_connection_name).merge(options).merge(:subscriber => subscriber, :action => action)
|
44
55
|
route_settings[:routing_key] ||= default_routing_key_for(route_settings)
|
45
56
|
route_settings[:queue] ||= default_queue_for(route_settings)
|
46
57
|
routes << Route.new(route_settings)
|
data/lib/action_subscriber.rb
CHANGED
@@ -25,9 +25,6 @@ require "action_subscriber/subscribable"
|
|
25
25
|
require "action_subscriber/bunny/subscriber"
|
26
26
|
require "action_subscriber/march_hare/subscriber"
|
27
27
|
require "action_subscriber/babou"
|
28
|
-
require "action_subscriber/publisher"
|
29
|
-
require "action_subscriber/publisher/async"
|
30
|
-
require "action_subscriber/synchronizer"
|
31
28
|
require "action_subscriber/route"
|
32
29
|
require "action_subscriber/route_set"
|
33
30
|
require "action_subscriber/router"
|
@@ -81,19 +78,21 @@ module ActionSubscriber
|
|
81
78
|
end
|
82
79
|
end
|
83
80
|
|
84
|
-
def self.
|
85
|
-
|
81
|
+
def self.setup_default_connection!
|
82
|
+
::ActionSubscriber::RabbitConnection.setup_connection(:default, {})
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.setup_subscriptions!
|
86
|
+
route_set.setup_subscriptions!
|
86
87
|
end
|
87
88
|
|
88
89
|
def self.start_queues
|
89
|
-
|
90
|
-
setup_queues!
|
90
|
+
setup_subscriptions!
|
91
91
|
print_subscriptions
|
92
92
|
end
|
93
93
|
|
94
94
|
def self.start_subscribers
|
95
|
-
|
96
|
-
setup_queues!
|
95
|
+
setup_subscriptions!
|
97
96
|
auto_subscribe!
|
98
97
|
print_subscriptions
|
99
98
|
end
|
@@ -106,21 +105,14 @@ module ActionSubscriber
|
|
106
105
|
require "action_subscriber/railtie" if defined?(Rails)
|
107
106
|
::ActiveSupport.run_load_hooks(:action_subscriber, Base)
|
108
107
|
|
109
|
-
# Intialize async publisher adapter
|
110
|
-
::ActionSubscriber::Publisher::Async.publisher_adapter
|
111
|
-
|
112
108
|
##
|
113
109
|
# Private Implementation
|
114
110
|
#
|
115
111
|
def self.route_set
|
116
112
|
@route_set ||= begin
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
else
|
121
|
-
logger.warn "DEPRECATION WARNING: We are inferring your routes by looking at your subscribers. This behavior is deprecated and will be removed in version 2.0. Please see the routing guide at https://github.com/mxenabled/action_subscriber/blob/master/routing.md"
|
122
|
-
RouteSet.new(self.send(:default_routes))
|
123
|
-
end
|
113
|
+
fail "cannot start because no routes have been defined. Please make sure that you call ActionSubscriber.draw_routes when your application loads" unless @draw_routes_block
|
114
|
+
routes = Router.draw_routes(&@draw_routes_block)
|
115
|
+
RouteSet.new(routes)
|
124
116
|
end
|
125
117
|
end
|
126
118
|
private_class_method :route_set
|
@@ -132,8 +124,3 @@ module ActionSubscriber
|
|
132
124
|
end
|
133
125
|
private_class_method :default_routes
|
134
126
|
end
|
135
|
-
|
136
|
-
at_exit do
|
137
|
-
::ActionSubscriber::Publisher::Async.publisher_adapter.shutdown!
|
138
|
-
::ActionSubscriber::RabbitConnection.publisher_disconnect!
|
139
|
-
end
|
@@ -32,7 +32,7 @@ describe "subscriber filters", :integration => true do
|
|
32
32
|
it "runs multiple around filters" do
|
33
33
|
$messages = [] #testing the order of things
|
34
34
|
::ActionSubscriber.auto_subscribe!
|
35
|
-
::
|
35
|
+
::ActivePublisher.publish("insta.first", "hEY Guyz!", "events")
|
36
36
|
|
37
37
|
verify_expectation_within(1.0) do
|
38
38
|
expect($messages).to eq [:whisper_before, :yell_before, "hEY Guyz!", :yell_after, :whisper_after]
|
@@ -17,7 +17,7 @@ describe "at_least_once! mode", :integration => true do
|
|
17
17
|
|
18
18
|
it "retries a failed job until it succeeds" do
|
19
19
|
::ActionSubscriber.auto_subscribe!
|
20
|
-
::
|
20
|
+
::ActivePublisher.publish("gorby_puff.grumpy", "GrumpFace", "events")
|
21
21
|
|
22
22
|
verify_expectation_within(2.0) do
|
23
23
|
expect($messages).to eq Set.new(["GrumpFace::0","GrumpFace::1","GrumpFace::2"])
|
@@ -17,7 +17,7 @@ describe "at_most_once! mode", :integration => true do
|
|
17
17
|
|
18
18
|
it "does not retry a failed message" do
|
19
19
|
::ActionSubscriber.auto_subscribe!
|
20
|
-
::
|
20
|
+
::ActivePublisher.publish("pokemon.caught_em_all", "All Pokemon have been caught", "events")
|
21
21
|
|
22
22
|
verify_expectation_within(1.0) do
|
23
23
|
expect($messages.size).to eq 1
|
@@ -7,7 +7,6 @@ class GusSubscriber < ActionSubscriber::Base
|
|
7
7
|
end
|
8
8
|
|
9
9
|
describe "Automatically reconnect on connection failure", :integration => true, :slow => true do
|
10
|
-
let(:connection) { subscriber.connection }
|
11
10
|
let(:draw_routes) do
|
12
11
|
::ActionSubscriber.draw_routes do
|
13
12
|
default_routes_for GusSubscriber
|
@@ -18,7 +17,7 @@ describe "Automatically reconnect on connection failure", :integration => true,
|
|
18
17
|
|
19
18
|
it "reconnects when a connection drops" do
|
20
19
|
::ActionSubscriber::auto_subscribe!
|
21
|
-
::
|
20
|
+
::ActivePublisher.publish("gus.spoke", "First", "events")
|
22
21
|
verify_expectation_within(5.0) do
|
23
22
|
expect($messages).to eq(Set.new(["First"]))
|
24
23
|
end
|
@@ -26,10 +25,10 @@ describe "Automatically reconnect on connection failure", :integration => true,
|
|
26
25
|
close_all_connections!
|
27
26
|
sleep 5.0
|
28
27
|
verify_expectation_within(5.0) do
|
29
|
-
expect(connection).to
|
28
|
+
expect(::ActionSubscriber::RabbitConnection.with_connection(:default){|connection| connection.open?}).to eq(true)
|
30
29
|
end
|
31
30
|
|
32
|
-
::
|
31
|
+
::ActivePublisher.publish("gus.spoke", "Second", "events")
|
33
32
|
verify_expectation_within(5.0) do
|
34
33
|
expect($messages).to eq(Set.new(["First", "Second"]))
|
35
34
|
end
|