action_subscriber 5.1.4-java → 5.2.2-java
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 +5 -5
- data/.travis.yml +7 -4
- data/README.md +1 -0
- data/lib/action_subscriber/bunny/subscriber.rb +43 -26
- data/lib/action_subscriber/configuration.rb +13 -2
- data/lib/action_subscriber/dsl.rb +45 -3
- data/lib/action_subscriber/march_hare/subscriber.rb +42 -24
- data/lib/action_subscriber/rabbit_connection.rb +23 -0
- data/lib/action_subscriber/version.rb +1 -1
- data/spec/integration/around_filters_spec.rb +87 -1
- data/spec/integration/consumer_cancellation_spec.rb +83 -0
- data/spec/lib/action_subscriber/configuration_spec.rb +7 -0
- data/spec/lib/action_subscriber/rabbit_connection_spec.rb +63 -0
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 69350b95fb8b203e390c3aac19dc9d53af00b2c517bd465b47c415633109b107
|
4
|
+
data.tar.gz: 5d93a16416a0cd14595ae0e0e029988154496575501862b4ecdd7469754004e6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 95909a21c18bdf27b56646b3431f200918618d30610dbab37d6afa6ca032e78695f603d9c8e3014f278346ce6493ee8e32f75526c3c51e71636d3d8595189b18
|
7
|
+
data.tar.gz: 680505cffe5b8b404b22e22246b104b58ef3e02cea0d0c501e56acb03d7daa3de03167067a9a26fa8147d89a8c12b89aab1b0cc98e3fd03f5bf6f0da21dd474b
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -135,6 +135,7 @@ Other configuration options include :
|
|
135
135
|
* config.network_recovery_interval - reconnection interval for TCP connection failures (default 1)
|
136
136
|
* config.password - RabbitMQ password (default "guest")
|
137
137
|
* config.prefetch - number of messages to hold in the local queue in subscriber mode
|
138
|
+
* config.resubscribe_on_consumer_cancellation - resubscribe when the consumer is cancelled (queue deleted or cluster fails, default true)
|
138
139
|
* config.seconds_to_wait_for_graceful_shutdown - time to wait before force stopping server after shutdown signal
|
139
140
|
* config.threadpool_size - set the number of threads available to action_subscriber
|
140
141
|
* config.timeout - how many seconds to allow rabbit to respond before timing out
|
@@ -26,35 +26,52 @@ module ActionSubscriber
|
|
26
26
|
|
27
27
|
def start_subscribers!
|
28
28
|
subscriptions.each do |subscription|
|
29
|
-
|
30
|
-
queue = subscription[:queue]
|
31
|
-
channel = queue.channel
|
32
|
-
threadpool = ::ActionSubscriber::ThreadPools.threadpools.fetch(route.threadpool_name)
|
33
|
-
channel.prefetch(route.prefetch) if route.acknowledgements?
|
34
|
-
consumer = ::Bunny::Consumer.new(channel, queue, channel.generate_consumer_tag, !route.acknowledgements?)
|
35
|
-
consumer.on_delivery do |delivery_info, properties, encoded_payload|
|
36
|
-
::ActiveSupport::Notifications.instrument "received_event.action_subscriber", :payload_size => encoded_payload.bytesize, :queue => queue.name
|
37
|
-
properties = {
|
38
|
-
:action => route.action,
|
39
|
-
:channel => queue.channel,
|
40
|
-
:content_type => properties.content_type,
|
41
|
-
:delivery_tag => delivery_info.delivery_tag,
|
42
|
-
:exchange => delivery_info.exchange,
|
43
|
-
:headers => properties.headers,
|
44
|
-
:message_id => properties.message_id,
|
45
|
-
:routing_key => delivery_info.routing_key,
|
46
|
-
:queue => queue.name,
|
47
|
-
:uses_acknowledgements => route.acknowledgements?,
|
48
|
-
}
|
49
|
-
env = ::ActionSubscriber::Middleware::Env.new(route.subscriber, encoded_payload, properties)
|
50
|
-
run_env(env, threadpool)
|
51
|
-
end
|
52
|
-
bunny_consumers << consumer
|
53
|
-
queue.subscribe_with(consumer)
|
29
|
+
start_subscriber_for_subscription(subscription)
|
54
30
|
end
|
55
31
|
end
|
56
32
|
|
57
|
-
|
33
|
+
private
|
34
|
+
|
35
|
+
def start_subscriber_for_subscription(subscription)
|
36
|
+
route = subscription[:route]
|
37
|
+
queue = subscription[:queue]
|
38
|
+
channel = queue.channel
|
39
|
+
threadpool = ::ActionSubscriber::ThreadPools.threadpools.fetch(route.threadpool_name)
|
40
|
+
channel.prefetch(route.prefetch) if route.acknowledgements?
|
41
|
+
consumer = ::Bunny::Consumer.new(channel, queue, channel.generate_consumer_tag, !route.acknowledgements?)
|
42
|
+
|
43
|
+
if ::ActionSubscriber.configuration.resubscribe_on_consumer_cancellation
|
44
|
+
# Add cancellation callback to rebuild subscriber on cancel.
|
45
|
+
consumer.on_cancellation do
|
46
|
+
::ActionSubscriber.logger.warn "Cancelation received for queue consumer: #{queue.name}, rebuilding subscription..."
|
47
|
+
bunny_consumers.delete(consumer)
|
48
|
+
channel.close
|
49
|
+
queue = subscription[:queue] = setup_queue(route)
|
50
|
+
start_subscriber_for_subscription(subscription)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
consumer.on_delivery do |delivery_info, properties, encoded_payload|
|
55
|
+
::ActiveSupport::Notifications.instrument "received_event.action_subscriber", :payload_size => encoded_payload.bytesize, :queue => queue.name
|
56
|
+
properties = {
|
57
|
+
:action => route.action,
|
58
|
+
:channel => queue.channel,
|
59
|
+
:content_type => properties.content_type,
|
60
|
+
:delivery_tag => delivery_info.delivery_tag,
|
61
|
+
:exchange => delivery_info.exchange,
|
62
|
+
:headers => properties.headers,
|
63
|
+
:message_id => properties.message_id,
|
64
|
+
:routing_key => delivery_info.routing_key,
|
65
|
+
:queue => queue.name,
|
66
|
+
:uses_acknowledgements => route.acknowledgements?,
|
67
|
+
}
|
68
|
+
env = ::ActionSubscriber::Middleware::Env.new(route.subscriber, encoded_payload, properties)
|
69
|
+
run_env(env, threadpool)
|
70
|
+
end
|
71
|
+
|
72
|
+
bunny_consumers << consumer
|
73
|
+
queue.subscribe_with(consumer)
|
74
|
+
end
|
58
75
|
|
59
76
|
def setup_queue(route)
|
60
77
|
channel = ::ActionSubscriber::RabbitConnection.with_connection{|connection| connection.create_channel(nil, 1) }
|
@@ -16,6 +16,7 @@ module ActionSubscriber
|
|
16
16
|
:password,
|
17
17
|
:port,
|
18
18
|
:prefetch,
|
19
|
+
:resubscribe_on_consumer_cancellation,
|
19
20
|
:seconds_to_wait_for_graceful_shutdown,
|
20
21
|
:threadpool_size,
|
21
22
|
:timeout,
|
@@ -42,6 +43,7 @@ module ActionSubscriber
|
|
42
43
|
:password => "guest",
|
43
44
|
:port => 5672,
|
44
45
|
:prefetch => 2,
|
46
|
+
:resubscribe_on_consumer_cancellation => true,
|
45
47
|
:seconds_to_wait_for_graceful_shutdown => 30,
|
46
48
|
:threadpool_size => 8,
|
47
49
|
:timeout => 1,
|
@@ -75,8 +77,8 @@ module ActionSubscriber
|
|
75
77
|
end
|
76
78
|
|
77
79
|
::ActionSubscriber::Configuration::DEFAULTS.each_pair do |key, value|
|
78
|
-
setting =
|
79
|
-
::ActionSubscriber.config.__send__("#{key}=", setting) if
|
80
|
+
exists, setting = fetch_config_value(key, cli_options, yaml_config)
|
81
|
+
::ActionSubscriber.config.__send__("#{key}=", setting) if exists
|
80
82
|
end
|
81
83
|
|
82
84
|
true
|
@@ -84,6 +86,15 @@ module ActionSubscriber
|
|
84
86
|
end
|
85
87
|
end
|
86
88
|
|
89
|
+
def self.fetch_config_value(key, cli_options, yaml_config)
|
90
|
+
return [true, cli_options[key]] if cli_options.key?(key)
|
91
|
+
return [true, cli_options[key.to_s]] if cli_options.key?(key.to_s)
|
92
|
+
return [true, yaml_config[key]] if yaml_config.key?(key)
|
93
|
+
return [true, yaml_config[key.to_s]] if yaml_config.key?(key.to_s)
|
94
|
+
[false, nil]
|
95
|
+
end
|
96
|
+
private_class_method :fetch_config_value
|
97
|
+
|
87
98
|
##
|
88
99
|
# Instance Methods
|
89
100
|
#
|
@@ -1,5 +1,38 @@
|
|
1
1
|
module ActionSubscriber
|
2
2
|
module DSL
|
3
|
+
class Filter
|
4
|
+
attr_accessor :callback_method
|
5
|
+
attr_accessor :included_actions
|
6
|
+
attr_accessor :excluded_actions
|
7
|
+
|
8
|
+
def initialize(callback_method, options)
|
9
|
+
@callback_method = callback_method
|
10
|
+
@included_actions = @excluded_actions = []
|
11
|
+
parse_options(options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def matches(action)
|
15
|
+
unless included_actions.empty?
|
16
|
+
return included_actions.include?(action)
|
17
|
+
end
|
18
|
+
|
19
|
+
unless excluded_actions.empty?
|
20
|
+
return false if excluded_actions.include?(action)
|
21
|
+
end
|
22
|
+
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def parse_options(options)
|
29
|
+
return unless options
|
30
|
+
|
31
|
+
@included_actions = options.fetch(:if, [])
|
32
|
+
@excluded_actions = options.fetch(:unless, [])
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
3
36
|
def at_least_once!
|
4
37
|
@_acknowledge_messages = true
|
5
38
|
@_at_least_once = true
|
@@ -22,11 +55,16 @@ module ActionSubscriber
|
|
22
55
|
!!@_acknowledge_messages
|
23
56
|
end
|
24
57
|
|
25
|
-
def around_filter(
|
26
|
-
|
58
|
+
def around_filter(callback_method, options = nil)
|
59
|
+
filter = Filter.new(callback_method, options)
|
60
|
+
conditionally_add_filter!(filter)
|
27
61
|
around_filters
|
28
62
|
end
|
29
63
|
|
64
|
+
def conditionally_add_filter!(filter)
|
65
|
+
around_filters << filter unless around_filters.any? { |f| f.callback_method == filter.callback_method }
|
66
|
+
end
|
67
|
+
|
30
68
|
def around_filters
|
31
69
|
@_around_filters ||= []
|
32
70
|
end
|
@@ -95,7 +133,11 @@ module ActionSubscriber
|
|
95
133
|
final_block = Proc.new { subscriber_instance.public_send(action) }
|
96
134
|
|
97
135
|
first_proc = around_filters.reverse.reduce(final_block) do |block, filter|
|
98
|
-
|
136
|
+
if filter.matches(action)
|
137
|
+
Proc.new { subscriber_instance.send(filter.callback_method, &block) }
|
138
|
+
else
|
139
|
+
block
|
140
|
+
end
|
99
141
|
end
|
100
142
|
first_proc.call
|
101
143
|
end
|
@@ -4,7 +4,8 @@ module ActionSubscriber
|
|
4
4
|
include ::ActionSubscriber::Logging
|
5
5
|
|
6
6
|
def cancel_consumers!
|
7
|
-
|
7
|
+
# Cancel any non-cancelled consumers.
|
8
|
+
march_hare_consumers.reject(&:cancelled?).each(&:cancel)
|
8
9
|
::ActionSubscriber::ThreadPools.threadpools.each do |name, threadpool|
|
9
10
|
threadpool.shutdown
|
10
11
|
end
|
@@ -26,33 +27,50 @@ module ActionSubscriber
|
|
26
27
|
|
27
28
|
def start_subscribers!
|
28
29
|
subscriptions.each do |subscription|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
30
|
+
start_subscriber_for_subscription(subscription)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def start_subscriber_for_subscription(subscription)
|
37
|
+
route = subscription[:route]
|
38
|
+
queue = subscription[:queue]
|
39
|
+
queue.channel.prefetch = route.prefetch if route.acknowledgements?
|
40
|
+
threadpool = ::ActionSubscriber::ThreadPools.threadpools.fetch(route.threadpool_name)
|
41
|
+
opts = route.queue_subscription_options
|
42
|
+
|
43
|
+
if ::ActionSubscriber.configuration.resubscribe_on_consumer_cancellation
|
44
|
+
# Add cancellation callback to rebuild subscriber on cancel.
|
45
|
+
opts[:on_cancellation] = lambda do |the_consumer|
|
46
|
+
::ActionSubscriber.logger.warn "Cancelation received for queue consumer: #{queue.name}, rebuilding subscription..."
|
47
|
+
march_hare_consumers.delete(the_consumer)
|
48
|
+
queue.channel.close
|
49
|
+
queue = subscription[:queue] = setup_queue(route)
|
50
|
+
start_subscriber_for_subscription(subscription)
|
49
51
|
end
|
52
|
+
end
|
50
53
|
|
51
|
-
|
54
|
+
consumer = queue.subscribe(opts) do |metadata, encoded_payload|
|
55
|
+
::ActiveSupport::Notifications.instrument "received_event.action_subscriber", :payload_size => encoded_payload.bytesize, :queue => queue.name
|
56
|
+
properties = {
|
57
|
+
:action => route.action,
|
58
|
+
:channel => queue.channel,
|
59
|
+
:content_type => metadata.content_type,
|
60
|
+
:delivery_tag => metadata.delivery_tag,
|
61
|
+
:exchange => metadata.exchange,
|
62
|
+
:headers => _normalized_headers(metadata),
|
63
|
+
:message_id => metadata.message_id,
|
64
|
+
:routing_key => metadata.routing_key,
|
65
|
+
:queue => queue.name,
|
66
|
+
:uses_acknowledgements => route.acknowledgements?,
|
67
|
+
}
|
68
|
+
env = ::ActionSubscriber::Middleware::Env.new(route.subscriber, encoded_payload, properties)
|
69
|
+
run_env(env, threadpool)
|
52
70
|
end
|
53
|
-
end
|
54
71
|
|
55
|
-
|
72
|
+
march_hare_consumers << consumer
|
73
|
+
end
|
56
74
|
|
57
75
|
def setup_queue(route)
|
58
76
|
channel = ::ActionSubscriber::RabbitConnection.with_connection{|connection| connection.create_channel }
|
@@ -30,9 +30,22 @@ module ActionSubscriber
|
|
30
30
|
::MarchHare::ThreadPools.fixed_of_size(options[:threadpool_size])
|
31
31
|
end
|
32
32
|
connection = ::MarchHare.connect(options)
|
33
|
+
connection.on_blocked do |reason|
|
34
|
+
on_blocked(reason)
|
35
|
+
end
|
36
|
+
connection.on_unblocked do
|
37
|
+
on_unblocked
|
38
|
+
end
|
39
|
+
connection
|
33
40
|
else
|
34
41
|
connection = ::Bunny.new(options)
|
35
42
|
connection.start
|
43
|
+
connection.on_blocked do |blocked_message|
|
44
|
+
on_blocked(blocked_message.reason)
|
45
|
+
end
|
46
|
+
connection.on_unblocked do
|
47
|
+
on_unblocked
|
48
|
+
end
|
36
49
|
connection
|
37
50
|
end
|
38
51
|
end
|
@@ -59,5 +72,15 @@ module ActionSubscriber
|
|
59
72
|
}
|
60
73
|
end
|
61
74
|
private_class_method :connection_options
|
75
|
+
|
76
|
+
def self.on_blocked(reason)
|
77
|
+
::ActiveSupport::Notifications.instrument("connection_blocked.action_subscriber", :reason => reason)
|
78
|
+
end
|
79
|
+
private_class_method :on_blocked
|
80
|
+
|
81
|
+
def self.on_unblocked
|
82
|
+
::ActiveSupport::Notifications.instrument("connection_unblocked.action_subscriber")
|
83
|
+
end
|
84
|
+
private_class_method :on_unblocked
|
62
85
|
end
|
63
86
|
end
|
@@ -33,7 +33,7 @@ describe "subscriber filters", :integration => true do
|
|
33
33
|
let(:subscriber) { InstaSubscriber }
|
34
34
|
|
35
35
|
it "does not allow an around filter to be pushed on twice" do
|
36
|
-
expect(InstaSubscriber.around_filters).to eq([:whisper, :yell])
|
36
|
+
expect(InstaSubscriber.around_filters.map(&:callback_method)).to eq([:whisper, :yell])
|
37
37
|
end
|
38
38
|
|
39
39
|
it "runs multiple around filters" do
|
@@ -46,3 +46,89 @@ describe "subscriber filters", :integration => true do
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
49
|
+
|
50
|
+
class OptionsSubscriber < ActionSubscriber::Base
|
51
|
+
around_filter :whisper, :if => [:primero, :segundo]
|
52
|
+
around_filter :yell, :if => [:primero]
|
53
|
+
around_filter :gossip, :unless => [:private_action]
|
54
|
+
around_filter :everybody
|
55
|
+
|
56
|
+
def primero
|
57
|
+
$messages << payload
|
58
|
+
end
|
59
|
+
|
60
|
+
def private_action
|
61
|
+
$messages << payload
|
62
|
+
end
|
63
|
+
|
64
|
+
def segundo
|
65
|
+
$messages << payload
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def everybody
|
71
|
+
$messages << :everybody_before
|
72
|
+
yield
|
73
|
+
$messages << :everybody_after
|
74
|
+
end
|
75
|
+
|
76
|
+
def gossip
|
77
|
+
$messages << :gossip_before
|
78
|
+
yield
|
79
|
+
$messages << :gossip_after
|
80
|
+
end
|
81
|
+
|
82
|
+
def whisper
|
83
|
+
$messages << :whisper_before
|
84
|
+
yield
|
85
|
+
$messages << :whisper_after
|
86
|
+
end
|
87
|
+
|
88
|
+
def yell
|
89
|
+
$messages << :yell_before
|
90
|
+
yield
|
91
|
+
$messages << :yell_after
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "subscriber filters with conditions", :integration => true do
|
96
|
+
let(:draw_routes) do
|
97
|
+
::ActionSubscriber.draw_routes do
|
98
|
+
default_routes_for OptionsSubscriber
|
99
|
+
end
|
100
|
+
end
|
101
|
+
let(:subscriber) { OptionsSubscriber }
|
102
|
+
|
103
|
+
context "honors conditions" do
|
104
|
+
it "runs yell" do
|
105
|
+
$messages = []
|
106
|
+
::ActionSubscriber.start_subscribers!
|
107
|
+
::ActivePublisher.publish("options.primero", "Howdy!", "events")
|
108
|
+
|
109
|
+
verify_expectation_within(1.0) do
|
110
|
+
expect($messages).to eq [:whisper_before, :yell_before, :gossip_before, :everybody_before, "Howdy!", :everybody_after, :gossip_after, :yell_after, :whisper_after]
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
it "doesn't yell" do
|
115
|
+
$messages = []
|
116
|
+
::ActionSubscriber.start_subscribers!
|
117
|
+
::ActivePublisher.publish("options.segundo", "Howdy!", "events")
|
118
|
+
|
119
|
+
verify_expectation_within(1.0) do
|
120
|
+
expect($messages).to eq [:whisper_before, :gossip_before, :everybody_before, "Howdy!", :everybody_after, :gossip_after, :whisper_after]
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
it "doesn't gossip" do
|
125
|
+
$messages = []
|
126
|
+
::ActionSubscriber.start_subscribers!
|
127
|
+
::ActivePublisher.publish("options.private_action", "Howdy!", "events")
|
128
|
+
|
129
|
+
verify_expectation_within(1.0) do
|
130
|
+
expect($messages).to eq [:everybody_before, "Howdy!", :everybody_after]
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "rabbitmq/http/client"
|
3
|
+
|
4
|
+
class YoloSubscriber < ActionSubscriber::Base
|
5
|
+
def created
|
6
|
+
$messages << payload
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "Automatically handles consumer cancellation", :integration => true, :slow => true do
|
11
|
+
let(:draw_routes) do
|
12
|
+
::ActionSubscriber.draw_routes do
|
13
|
+
default_routes_for ::YoloSubscriber
|
14
|
+
end
|
15
|
+
end
|
16
|
+
let(:http_client) { ::RabbitMQ::HTTP::Client.new("http://127.0.0.1:15672") }
|
17
|
+
let(:subscriber) { ::YoloSubscriber }
|
18
|
+
|
19
|
+
it "resubscribes on cancellation" do
|
20
|
+
::ActionSubscriber::start_subscribers!
|
21
|
+
::ActivePublisher.publish("yolo.created", "First", "events")
|
22
|
+
verify_expectation_within(5.0) do
|
23
|
+
expect($messages).to eq(::Set.new(["First"]))
|
24
|
+
end
|
25
|
+
|
26
|
+
consumers = rabbit_consumers.dup
|
27
|
+
|
28
|
+
# Signal a cancellation event to all subscribers.
|
29
|
+
delete_all_queues!
|
30
|
+
|
31
|
+
# Give consumers a chance to restart.
|
32
|
+
sleep 2.0
|
33
|
+
|
34
|
+
expect(rabbit_consumers).to_not eq(consumers)
|
35
|
+
|
36
|
+
::ActivePublisher.publish("yolo.created", "Second", "events")
|
37
|
+
verify_expectation_within(5.0) do
|
38
|
+
expect($messages).to eq(Set.new(["First", "Second"]))
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "when resubscribe on consumer cancellation is disabled" do
|
43
|
+
before do
|
44
|
+
allow(::ActionSubscriber.configuration).to receive(:resubscribe_on_consumer_cancellation).and_return(false)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "does not resubscribe on cancellation" do
|
48
|
+
::ActionSubscriber::start_subscribers!
|
49
|
+
::ActivePublisher.publish("yolo.created", "First", "events")
|
50
|
+
verify_expectation_within(5.0) do
|
51
|
+
expect($messages).to eq(::Set.new(["First"]))
|
52
|
+
end
|
53
|
+
|
54
|
+
consumers = rabbit_consumers.dup
|
55
|
+
|
56
|
+
# Signal a cancellation event to all subscribers.
|
57
|
+
delete_all_queues!
|
58
|
+
|
59
|
+
# Give consumers a chance to restart.
|
60
|
+
sleep 2.0
|
61
|
+
|
62
|
+
# Verify the consumers did not change.
|
63
|
+
expect(rabbit_consumers).to eq(consumers)
|
64
|
+
|
65
|
+
::ActivePublisher.publish("yolo.created", "Second", "events")
|
66
|
+
|
67
|
+
# Force sleep 2 seconds to ensure a resubscribe did not happen and messages were not processed.
|
68
|
+
sleep 2.0
|
69
|
+
expect($messages).to eq(Set.new(["First"]))
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def rabbit_consumers
|
74
|
+
route_set = ::ActionSubscriber.send(:route_set)
|
75
|
+
route_set.try(:bunny_consumers) || route_set.try(:march_hare_consumers)
|
76
|
+
end
|
77
|
+
|
78
|
+
def delete_all_queues!
|
79
|
+
http_client.list_queues.each do |queue|
|
80
|
+
http_client.delete_queue(queue.vhost, queue.name)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -24,6 +24,13 @@ describe ::ActionSubscriber::Configuration do
|
|
24
24
|
::ActionSubscriber::Configuration.configure_from_yaml_and_cli({}, true)
|
25
25
|
end
|
26
26
|
end
|
27
|
+
|
28
|
+
it "can override a true value with a false value" do
|
29
|
+
expect(::ActionSubscriber.configuration.verify_peer).to eq(true)
|
30
|
+
expect(::ActionSubscriber.configuration).to receive(:verify_peer=).with(false).and_call_original
|
31
|
+
::ActionSubscriber::Configuration.configure_from_yaml_and_cli({"verify_peer" => false}, true)
|
32
|
+
expect(::ActionSubscriber.configuration.verify_peer).to eq(false)
|
33
|
+
end
|
27
34
|
end
|
28
35
|
|
29
36
|
describe "add_decoder" do
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe ::ActionSubscriber::RabbitConnection do
|
4
|
+
let(:reason) { "low on disk" }
|
5
|
+
|
6
|
+
before { ActionSubscriber.draw_routes {} }
|
7
|
+
|
8
|
+
context "on_block" do
|
9
|
+
if ::RUBY_PLATFORM == "java"
|
10
|
+
def trigger_mocked_blocking_event(connection, reason)
|
11
|
+
amqp_message = ::Java::ComRabbitmqClient::AMQP::Connection::Blocked::Builder.new.
|
12
|
+
reason(reason).build
|
13
|
+
amq_command = ::Java::ComRabbitmqClientImpl::AMQCommand.new(amqp_message)
|
14
|
+
|
15
|
+
connection.send(:processControlCommand, amq_command)
|
16
|
+
end
|
17
|
+
else
|
18
|
+
def trigger_mocked_blocking_event(connection, reason)
|
19
|
+
connection.send(:handle_frame, 0, ::AMQ::Protocol::Connection::Blocked.new(reason))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it "can deliver an on_blocked message" do
|
24
|
+
expect(::ActiveSupport::Notifications).to receive(:instrument).
|
25
|
+
with("connection_blocked.action_subscriber", :reason => reason)
|
26
|
+
|
27
|
+
described_class.with_connection do |connection|
|
28
|
+
# NOTE: Trigger the receiving of a blocked message from the broker.
|
29
|
+
# It's a bit of a hack but it is a more realistic test without changing
|
30
|
+
# memory alarms.
|
31
|
+
trigger_mocked_blocking_event(connection, reason)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "on_unblocked" do
|
37
|
+
if ::RUBY_PLATFORM == "java"
|
38
|
+
def trigger_mocked_unblocked_event(connection, reason)
|
39
|
+
amqp_message = ::Java::ComRabbitmqClient::AMQP::Connection::Unblocked::Builder.new.
|
40
|
+
build
|
41
|
+
amq_command = ::Java::ComRabbitmqClientImpl::AMQCommand.new(amqp_message)
|
42
|
+
|
43
|
+
connection.send(:processControlCommand, amq_command)
|
44
|
+
end
|
45
|
+
else
|
46
|
+
def trigger_mocked_unblocked_event(connection, reason)
|
47
|
+
connection.send(:handle_frame, 0, ::AMQ::Protocol::Connection::Unblocked.new)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
it "can deliver an on_unblocked message" do
|
52
|
+
expect(::ActiveSupport::Notifications).to receive(:instrument).
|
53
|
+
with("connection_unblocked.action_subscriber")
|
54
|
+
|
55
|
+
described_class.with_connection do |connection|
|
56
|
+
# NOTE: Trigger the receiving of an unblocked message from the broker.
|
57
|
+
# It's a bit of a hack but it is a more realistic test without changing
|
58
|
+
# memory alarms.
|
59
|
+
trigger_mocked_unblocked_event(connection, reason)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: action_subscriber
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.2.2
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Brian Stien
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
|
-
date:
|
15
|
+
date: 2020-07-29 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
requirement: !ruby/object:Gem::Requirement
|
@@ -258,6 +258,7 @@ files:
|
|
258
258
|
- spec/integration/at_most_once_spec.rb
|
259
259
|
- spec/integration/automatic_reconnect_spec.rb
|
260
260
|
- spec/integration/basic_subscriber_spec.rb
|
261
|
+
- spec/integration/consumer_cancellation_spec.rb
|
261
262
|
- spec/integration/custom_actions_spec.rb
|
262
263
|
- spec/integration/custom_headers_spec.rb
|
263
264
|
- spec/integration/decoding_payloads_spec.rb
|
@@ -272,6 +273,7 @@ files:
|
|
272
273
|
- spec/lib/action_subscriber/middleware/error_handler_spec.rb
|
273
274
|
- spec/lib/action_subscriber/middleware/router_spec.rb
|
274
275
|
- spec/lib/action_subscriber/middleware/runner_spec.rb
|
276
|
+
- spec/lib/action_subscriber/rabbit_connection_spec.rb
|
275
277
|
- spec/lib/action_subscriber/router_spec.rb
|
276
278
|
- spec/lib/action_subscriber/subscribable_spec.rb
|
277
279
|
- spec/spec_helper.rb
|
@@ -297,7 +299,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
297
299
|
version: '0'
|
298
300
|
requirements: []
|
299
301
|
rubyforge_project:
|
300
|
-
rubygems_version: 2.
|
302
|
+
rubygems_version: 2.7.9
|
301
303
|
signing_key:
|
302
304
|
specification_version: 4
|
303
305
|
summary: ActionSubscriber is a DSL that allows a rails app to consume messages from
|
@@ -308,6 +310,7 @@ test_files:
|
|
308
310
|
- spec/integration/at_most_once_spec.rb
|
309
311
|
- spec/integration/automatic_reconnect_spec.rb
|
310
312
|
- spec/integration/basic_subscriber_spec.rb
|
313
|
+
- spec/integration/consumer_cancellation_spec.rb
|
311
314
|
- spec/integration/custom_actions_spec.rb
|
312
315
|
- spec/integration/custom_headers_spec.rb
|
313
316
|
- spec/integration/decoding_payloads_spec.rb
|
@@ -322,6 +325,7 @@ test_files:
|
|
322
325
|
- spec/lib/action_subscriber/middleware/error_handler_spec.rb
|
323
326
|
- spec/lib/action_subscriber/middleware/router_spec.rb
|
324
327
|
- spec/lib/action_subscriber/middleware/runner_spec.rb
|
328
|
+
- spec/lib/action_subscriber/rabbit_connection_spec.rb
|
325
329
|
- spec/lib/action_subscriber/router_spec.rb
|
326
330
|
- spec/lib/action_subscriber/subscribable_spec.rb
|
327
331
|
- spec/spec_helper.rb
|