action_subscriber 2.5.0.pre-java → 3.0.0-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 +4 -4
- data/.travis.yml +1 -2
- data/README.md +15 -23
- data/action_subscriber.gemspec +1 -0
- data/lib/action_subscriber.rb +11 -23
- data/lib/action_subscriber/babou.rb +2 -29
- data/lib/action_subscriber/base.rb +0 -4
- data/lib/action_subscriber/bunny/subscriber.rb +18 -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 +20 -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 +20 -4
- data/lib/action_subscriber/rabbit_connection.rb +24 -33
- data/lib/action_subscriber/route.rb +5 -1
- data/lib/action_subscriber/route_set.rb +13 -6
- data/lib/action_subscriber/router.rb +15 -3
- data/lib/action_subscriber/version.rb +1 -1
- 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/lib/action_subscriber/middleware/error_handler_spec.rb +15 -0
- data/spec/spec_helper.rb +8 -4
- metadata +21 -16
- data/lib/action_subscriber/publisher.rb +0 -46
- data/lib/action_subscriber/publisher/async.rb +0 -31
- data/lib/action_subscriber/publisher/async/in_memory_adapter.rb +0 -153
- 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
data/spec/spec_helper.rb
CHANGED
@@ -15,6 +15,7 @@ require 'action_subscriber/rspec'
|
|
15
15
|
# Silence the Logger
|
16
16
|
$TESTING = true
|
17
17
|
::ActionSubscriber::Logging.initialize_logger(nil)
|
18
|
+
::ActionSubscriber.setup_default_connection!
|
18
19
|
|
19
20
|
RSpec.configure do |config|
|
20
21
|
config.mock_with :rspec do |mocks|
|
@@ -23,14 +24,17 @@ RSpec.configure do |config|
|
|
23
24
|
|
24
25
|
config.before(:each, :integration => true) do
|
25
26
|
$messages = Set.new
|
26
|
-
draw_routes
|
27
|
-
::ActionSubscriber
|
28
|
-
::ActionSubscriber.setup_queues!
|
27
|
+
draw_routes
|
28
|
+
::ActionSubscriber.setup_subscriptions!
|
29
29
|
end
|
30
30
|
config.after(:each, :integration => true) do
|
31
31
|
::ActionSubscriber.stop_subscribers!
|
32
|
-
::ActionSubscriber::RabbitConnection.subscriber_disconnect!
|
33
32
|
::ActionSubscriber.instance_variable_set("@route_set", nil)
|
33
|
+
::ActionSubscriber.instance_variable_set("@route_set_block", nil)
|
34
|
+
end
|
35
|
+
config.after(:suite) do
|
36
|
+
::ActionSubscriber.stop_subscribers!
|
37
|
+
::ActionSubscriber::RabbitConnection.subscriber_disconnect!
|
34
38
|
end
|
35
39
|
end
|
36
40
|
|
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:
|
4
|
+
version: 3.0.0
|
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: 2016-09-
|
15
|
+
date: 2016-09-22 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
requirement: !ruby/object:Gem::Requirement
|
@@ -84,6 +84,20 @@ dependencies:
|
|
84
84
|
- - ">="
|
85
85
|
- !ruby/object:Gem::Version
|
86
86
|
version: '0'
|
87
|
+
- !ruby/object:Gem::Dependency
|
88
|
+
requirement: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - "~>"
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: 0.1.5
|
93
|
+
name: active_publisher
|
94
|
+
prerelease: false
|
95
|
+
type: :development
|
96
|
+
version_requirements: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - "~>"
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: 0.1.5
|
87
101
|
- !ruby/object:Gem::Dependency
|
88
102
|
requirement: !ruby/object:Gem::Requirement
|
89
103
|
requirements:
|
@@ -213,9 +227,6 @@ files:
|
|
213
227
|
- lib/action_subscriber/middleware/router.rb
|
214
228
|
- lib/action_subscriber/middleware/runner.rb
|
215
229
|
- lib/action_subscriber/preload.rb
|
216
|
-
- lib/action_subscriber/publisher.rb
|
217
|
-
- lib/action_subscriber/publisher/async.rb
|
218
|
-
- lib/action_subscriber/publisher/async/in_memory_adapter.rb
|
219
230
|
- lib/action_subscriber/rabbit_connection.rb
|
220
231
|
- lib/action_subscriber/railtie.rb
|
221
232
|
- lib/action_subscriber/route.rb
|
@@ -235,8 +246,8 @@ files:
|
|
235
246
|
- spec/integration/custom_actions_spec.rb
|
236
247
|
- spec/integration/custom_headers_spec.rb
|
237
248
|
- spec/integration/decoding_payloads_spec.rb
|
238
|
-
- spec/integration/inferred_routes_spec.rb
|
239
249
|
- spec/integration/manual_acknowledgement_spec.rb
|
250
|
+
- spec/integration/multiple_connections_spec.rb
|
240
251
|
- spec/integration/multiple_threadpools_spec.rb
|
241
252
|
- spec/lib/action_subscriber/base_spec.rb
|
242
253
|
- spec/lib/action_subscriber/configuration_spec.rb
|
@@ -248,9 +259,6 @@ files:
|
|
248
259
|
- spec/lib/action_subscriber/middleware/error_handler_spec.rb
|
249
260
|
- spec/lib/action_subscriber/middleware/router_spec.rb
|
250
261
|
- spec/lib/action_subscriber/middleware/runner_spec.rb
|
251
|
-
- spec/lib/action_subscriber/publisher/async/in_memory_adapter_spec.rb
|
252
|
-
- spec/lib/action_subscriber/publisher/async_spec.rb
|
253
|
-
- spec/lib/action_subscriber/publisher_spec.rb
|
254
262
|
- spec/lib/action_subscriber/router_spec.rb
|
255
263
|
- spec/lib/action_subscriber/subscribable_spec.rb
|
256
264
|
- spec/lib/action_subscriber/threadpool_spec.rb
|
@@ -271,12 +279,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
271
279
|
version: '0'
|
272
280
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
273
281
|
requirements:
|
274
|
-
- - "
|
282
|
+
- - ">="
|
275
283
|
- !ruby/object:Gem::Version
|
276
|
-
version:
|
284
|
+
version: '0'
|
277
285
|
requirements: []
|
278
286
|
rubyforge_project:
|
279
|
-
rubygems_version: 2.6.
|
287
|
+
rubygems_version: 2.6.6
|
280
288
|
signing_key:
|
281
289
|
specification_version: 4
|
282
290
|
summary: ActionSubscriber is a DSL that allows a rails app to consume messages from a RabbitMQ broker.
|
@@ -289,8 +297,8 @@ test_files:
|
|
289
297
|
- spec/integration/custom_actions_spec.rb
|
290
298
|
- spec/integration/custom_headers_spec.rb
|
291
299
|
- spec/integration/decoding_payloads_spec.rb
|
292
|
-
- spec/integration/inferred_routes_spec.rb
|
293
300
|
- spec/integration/manual_acknowledgement_spec.rb
|
301
|
+
- spec/integration/multiple_connections_spec.rb
|
294
302
|
- spec/integration/multiple_threadpools_spec.rb
|
295
303
|
- spec/lib/action_subscriber/base_spec.rb
|
296
304
|
- spec/lib/action_subscriber/configuration_spec.rb
|
@@ -302,9 +310,6 @@ test_files:
|
|
302
310
|
- spec/lib/action_subscriber/middleware/error_handler_spec.rb
|
303
311
|
- spec/lib/action_subscriber/middleware/router_spec.rb
|
304
312
|
- spec/lib/action_subscriber/middleware/runner_spec.rb
|
305
|
-
- spec/lib/action_subscriber/publisher/async/in_memory_adapter_spec.rb
|
306
|
-
- spec/lib/action_subscriber/publisher/async_spec.rb
|
307
|
-
- spec/lib/action_subscriber/publisher_spec.rb
|
308
313
|
- spec/lib/action_subscriber/router_spec.rb
|
309
314
|
- spec/lib/action_subscriber/subscribable_spec.rb
|
310
315
|
- spec/lib/action_subscriber/threadpool_spec.rb
|
@@ -1,46 +0,0 @@
|
|
1
|
-
module ActionSubscriber
|
2
|
-
module Publisher
|
3
|
-
# Publish a message to RabbitMQ
|
4
|
-
#
|
5
|
-
# @param [String] route The routing key to use for this message.
|
6
|
-
# @param [String] payload The message you are sending. Should already be encoded as a string.
|
7
|
-
# @param [String] exchange The exchange you want to publish to.
|
8
|
-
# @param [Hash] options hash to set message parameters (e.g. headers)
|
9
|
-
def self.publish(route, payload, exchange_name, options = {})
|
10
|
-
with_exchange(exchange_name) do |exchange|
|
11
|
-
exchange.publish(payload, publishing_options(route, options))
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.with_exchange(exchange_name)
|
16
|
-
connection = RabbitConnection.publisher_connection
|
17
|
-
channel = connection.create_channel
|
18
|
-
begin
|
19
|
-
channel.confirm_select if ActionSubscriber.configuration.publisher_confirms
|
20
|
-
exchange = channel.topic(exchange_name)
|
21
|
-
yield(exchange)
|
22
|
-
channel.wait_for_confirms if ActionSubscriber.configuration.publisher_confirms
|
23
|
-
ensure
|
24
|
-
channel.close rescue nil
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def self.publishing_options(route, in_options = {})
|
29
|
-
options = {
|
30
|
-
:mandatory => false,
|
31
|
-
:persistent => false,
|
32
|
-
:routing_key => route,
|
33
|
-
}.merge(in_options)
|
34
|
-
|
35
|
-
if ::RUBY_PLATFORM == "java"
|
36
|
-
java_options = {}
|
37
|
-
java_options[:mandatory] = options.delete(:mandatory)
|
38
|
-
java_options[:routing_key] = options.delete(:routing_key)
|
39
|
-
java_options[:properties] = options
|
40
|
-
java_options
|
41
|
-
else
|
42
|
-
options
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
module ActionSubscriber
|
2
|
-
module Publisher
|
3
|
-
# Publish a message asynchronously to RabbitMQ.
|
4
|
-
#
|
5
|
-
# Asynchronous is designed to do two things:
|
6
|
-
# 1. Introduce the idea of a durable retry should the RabbitMQ connection disconnect.
|
7
|
-
# 2. Provide a higher-level pattern for fire-and-forget publishing.
|
8
|
-
#
|
9
|
-
# @param [String] route The routing key to use for this message.
|
10
|
-
# @param [String] payload The message you are sending. Should already be encoded as a string.
|
11
|
-
# @param [String] exchange The exchange you want to publish to.
|
12
|
-
# @param [Hash] options hash to set message parameters (e.g. headers).
|
13
|
-
def self.publish_async(route, payload, exchange_name, options = {})
|
14
|
-
Async.publisher_adapter.publish(route, payload, exchange_name, options)
|
15
|
-
end
|
16
|
-
|
17
|
-
module Async
|
18
|
-
def self.publisher_adapter
|
19
|
-
@publisher_adapter ||= case ::ActionSubscriber.configuration.async_publisher
|
20
|
-
when /memory/i then
|
21
|
-
require "action_subscriber/publisher/async/in_memory_adapter"
|
22
|
-
InMemoryAdapter.new
|
23
|
-
when /redis/i then
|
24
|
-
fail "Not yet implemented"
|
25
|
-
else
|
26
|
-
fail "Unknown adapter '#{::ActionSubscriber.configuration.async_publisher}' provided"
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,153 +0,0 @@
|
|
1
|
-
require "thread"
|
2
|
-
|
3
|
-
module ActionSubscriber
|
4
|
-
module Publisher
|
5
|
-
module Async
|
6
|
-
class InMemoryAdapter
|
7
|
-
include ::ActionSubscriber::Logging
|
8
|
-
|
9
|
-
attr_reader :async_queue
|
10
|
-
|
11
|
-
def initialize
|
12
|
-
logger.info "Starting in-memory publisher adapter."
|
13
|
-
|
14
|
-
@async_queue = AsyncQueue.new
|
15
|
-
end
|
16
|
-
|
17
|
-
def publish(route, payload, exchange_name, options = {})
|
18
|
-
message = Message.new(route, payload, exchange_name, options)
|
19
|
-
async_queue.push(message)
|
20
|
-
nil
|
21
|
-
end
|
22
|
-
|
23
|
-
def shutdown!
|
24
|
-
max_wait_time = ::ActionSubscriber.configuration.seconds_to_wait_for_graceful_shutdown
|
25
|
-
started_shutting_down_at = ::Time.now
|
26
|
-
|
27
|
-
logger.info "Draining async publisher in-memory adapter queue before shutdown. Current queue size: #{async_queue.size}."
|
28
|
-
while async_queue.size > 0
|
29
|
-
if (::Time.now - started_shutting_down_at) > max_wait_time
|
30
|
-
logger.info "Forcing async publisher adapter shutdown because graceful shutdown period of #{max_wait_time} seconds was exceeded. Current queue size: #{async_queue.size}."
|
31
|
-
break
|
32
|
-
end
|
33
|
-
|
34
|
-
sleep 0.1
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
class Message
|
39
|
-
attr_reader :route, :payload, :exchange_name, :options
|
40
|
-
|
41
|
-
def initialize(route, payload, exchange_name, options)
|
42
|
-
@route = route
|
43
|
-
@payload = payload
|
44
|
-
@exchange_name = exchange_name
|
45
|
-
@options = options
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
class UnableToPersistMessageError < ::StandardError
|
50
|
-
end
|
51
|
-
|
52
|
-
class AsyncQueue
|
53
|
-
include ::ActionSubscriber::Logging
|
54
|
-
|
55
|
-
attr_reader :consumer, :queue, :supervisor
|
56
|
-
|
57
|
-
if ::RUBY_PLATFORM == "java"
|
58
|
-
NETWORK_ERRORS = [::MarchHare::Exception, ::Java::ComRabbitmqClient::AlreadyClosedException, ::Java::JavaIo::IOException].freeze
|
59
|
-
else
|
60
|
-
NETWORK_ERRORS = [::Bunny::Exception, ::Timeout::Error, ::IOError].freeze
|
61
|
-
end
|
62
|
-
|
63
|
-
def initialize
|
64
|
-
@queue = ::Queue.new
|
65
|
-
create_and_supervise_consumer!
|
66
|
-
end
|
67
|
-
|
68
|
-
def push(message)
|
69
|
-
# Default of 1_000_000 messages.
|
70
|
-
if queue.size > ::ActionSubscriber.configuration.async_publisher_max_queue_size
|
71
|
-
# Drop Messages if the queue is full and we were configured to do so.
|
72
|
-
return if ::ActionSubscriber.configuration.async_publisher_drop_messages_when_queue_full
|
73
|
-
|
74
|
-
# By default we will raise an error to push the responsibility onto the caller.
|
75
|
-
fail UnableToPersistMessageError, "Queue is full, messages will be dropped."
|
76
|
-
end
|
77
|
-
|
78
|
-
queue.push(message)
|
79
|
-
end
|
80
|
-
|
81
|
-
def size
|
82
|
-
queue.size
|
83
|
-
end
|
84
|
-
|
85
|
-
private
|
86
|
-
|
87
|
-
def await_network_reconnect
|
88
|
-
sleep ::ActionSubscriber::RabbitConnection::NETWORK_RECOVERY_INTERVAL
|
89
|
-
end
|
90
|
-
|
91
|
-
def create_and_supervise_consumer!
|
92
|
-
@consumer = create_consumer
|
93
|
-
@supervisor = ::Thread.new do
|
94
|
-
loop do
|
95
|
-
unless consumer.alive?
|
96
|
-
# Why might need to requeue the last message.
|
97
|
-
queue.push(@current_message) if @current_message.present?
|
98
|
-
consumer.kill
|
99
|
-
@consumer = create_consumer
|
100
|
-
end
|
101
|
-
|
102
|
-
# Pause before checking the consumer again.
|
103
|
-
sleep supervisor_interval
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def create_consumer
|
109
|
-
::Thread.new do
|
110
|
-
loop do
|
111
|
-
# Write "current_message" so we can requeue should something happen to the consumer. I don't love this, but it's
|
112
|
-
# better than writing my own `#peek' method.
|
113
|
-
@current_message = message = queue.pop
|
114
|
-
|
115
|
-
begin
|
116
|
-
::ActionSubscriber::Publisher.publish(message.route, message.payload, message.exchange_name, message.options)
|
117
|
-
|
118
|
-
# Reset
|
119
|
-
@current_message = nil
|
120
|
-
rescue *NETWORK_ERRORS
|
121
|
-
# Sleep because the connection is down.
|
122
|
-
await_network_reconnect
|
123
|
-
|
124
|
-
# Requeue and try again.
|
125
|
-
queue.push(message)
|
126
|
-
rescue => unknown_error
|
127
|
-
# Do not requeue the message because something else horrible happened.
|
128
|
-
@current_message = nil
|
129
|
-
|
130
|
-
# Log the error.
|
131
|
-
logger.info unknown_error.class
|
132
|
-
logger.info unknown_error.message
|
133
|
-
logger.info unknown_error.backtrace.join("\n")
|
134
|
-
|
135
|
-
# TODO: Find a way to bubble this out of the thread for logging purposes.
|
136
|
-
# Reraise the error out of the publisher loop. The Supervisor will restart the consumer.
|
137
|
-
raise unknown_error
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
def supervisor_interval
|
144
|
-
@supervisor_interval ||= begin
|
145
|
-
interval_in_milliseconds = ::ActionSubscriber.configuration.async_publisher_supervisor_interval
|
146
|
-
interval_in_milliseconds / 1000.0
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
153
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
class InferenceSubscriber < ActionSubscriber::Base
|
2
|
-
publisher :kyle
|
3
|
-
|
4
|
-
def yo
|
5
|
-
$messages << payload
|
6
|
-
end
|
7
|
-
|
8
|
-
queue_for :hey, "some_other_queue.hey"
|
9
|
-
routing_key_for :hey, "other_routing_key.hey"
|
10
|
-
def hey
|
11
|
-
$messages << payload
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
describe "A Subscriber With Inferred Routes", :integration => true do
|
16
|
-
context "explicit routing with default_routes_for helper" do
|
17
|
-
let(:draw_routes) do
|
18
|
-
::ActionSubscriber.draw_routes do
|
19
|
-
default_routes_for InferenceSubscriber
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
it "registers the routes and sets up the queues" do
|
24
|
-
::ActionSubscriber.auto_subscribe!
|
25
|
-
::ActionSubscriber::Publisher.publish("kyle.inference.yo", "YO", "events")
|
26
|
-
::ActionSubscriber::Publisher.publish("other_routing_key.hey", "HEY", "events")
|
27
|
-
|
28
|
-
verify_expectation_within(2.0) do
|
29
|
-
expect($messages).to eq(Set.new(["YO","HEY"]))
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
# This is the deprecated behavior we want to keep until version 2.0
|
35
|
-
context "no explicit routes" do
|
36
|
-
before do
|
37
|
-
# TEST HACK: Bust any memoized routes.
|
38
|
-
::ActionSubscriber.instance_variable_set(:@route_set, nil)
|
39
|
-
::ActionSubscriber.instance_variable_set(:@draw_routes_block, nil)
|
40
|
-
::ActionSubscriber.setup_queues!
|
41
|
-
end
|
42
|
-
|
43
|
-
it "registers the routes and sets up the queues" do
|
44
|
-
::ActionSubscriber.auto_subscribe!
|
45
|
-
::ActionSubscriber::Publisher.publish("kyle.inference.yo", "YO", "events")
|
46
|
-
::ActionSubscriber::Publisher.publish("other_routing_key.hey", "HEY", "events")
|
47
|
-
|
48
|
-
verify_expectation_within(2.0) do
|
49
|
-
expect($messages).to eq(Set.new(["YO","HEY"]))
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
@@ -1,135 +0,0 @@
|
|
1
|
-
describe ::ActionSubscriber::Publisher::Async::InMemoryAdapter do
|
2
|
-
let(:route) { "test" }
|
3
|
-
let(:payload) { "message" }
|
4
|
-
let(:exchange_name) { "place" }
|
5
|
-
let(:options) { { :test => :ok } }
|
6
|
-
let(:message) { described_class::Message.new(route, payload, exchange_name, options) }
|
7
|
-
let(:mock_queue) { double(:push => nil, :size => 0) }
|
8
|
-
|
9
|
-
describe "#publish" do
|
10
|
-
before do
|
11
|
-
allow(described_class::Message).to receive(:new).with(route, payload, exchange_name, options).and_return(message)
|
12
|
-
allow(described_class::AsyncQueue).to receive(:new).and_return(mock_queue)
|
13
|
-
end
|
14
|
-
|
15
|
-
it "can publish a message to the queue" do
|
16
|
-
expect(mock_queue).to receive(:push).with(message)
|
17
|
-
subject.publish(route, payload, exchange_name, options)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
describe "#shutdown!" do
|
22
|
-
# This is called when the rspec finishes. I'm sure we can make this a better test.
|
23
|
-
end
|
24
|
-
|
25
|
-
describe "::ActionSubscriber::Publisher::Async::InMemoryAdapter::Message" do
|
26
|
-
specify { expect(message.route).to eq(route) }
|
27
|
-
specify { expect(message.payload).to eq(payload) }
|
28
|
-
specify { expect(message.exchange_name).to eq(exchange_name) }
|
29
|
-
specify { expect(message.options).to eq(options) }
|
30
|
-
end
|
31
|
-
|
32
|
-
describe "::ActionSubscriber::Publisher::Async::InMemoryAdapter::AsyncQueue" do
|
33
|
-
subject { described_class::AsyncQueue.new }
|
34
|
-
|
35
|
-
describe ".initialize" do
|
36
|
-
it "creates a supervisor" do
|
37
|
-
expect_any_instance_of(described_class::AsyncQueue).to receive(:create_and_supervise_consumer!)
|
38
|
-
subject
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
describe "#create_and_supervise_consumer!" do
|
43
|
-
it "creates a supervisor" do
|
44
|
-
expect_any_instance_of(described_class::AsyncQueue).to receive(:create_consumer)
|
45
|
-
subject
|
46
|
-
end
|
47
|
-
|
48
|
-
it "restarts the consumer when it dies" do
|
49
|
-
consumer = subject.consumer
|
50
|
-
consumer.kill
|
51
|
-
|
52
|
-
verify_expectation_within(0.1) do
|
53
|
-
expect(consumer).to_not be_alive
|
54
|
-
end
|
55
|
-
|
56
|
-
verify_expectation_within(0.3) do
|
57
|
-
expect(subject.consumer).to be_alive
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
describe "#create_consumer" do
|
63
|
-
it "can successfully publish a message" do
|
64
|
-
expect(::ActionSubscriber::Publisher).to receive(:publish).with(route, payload, exchange_name, options)
|
65
|
-
subject.push(message)
|
66
|
-
sleep 0.1 # Await results
|
67
|
-
end
|
68
|
-
|
69
|
-
context "when network error occurs" do
|
70
|
-
let(:error) { described_class::AsyncQueue::NETWORK_ERRORS.first }
|
71
|
-
before { allow(::ActionSubscriber::Publisher).to receive(:publish).and_raise(error) }
|
72
|
-
|
73
|
-
it "requeues the message" do
|
74
|
-
consumer = subject.consumer
|
75
|
-
expect(consumer).to be_alive
|
76
|
-
expect(subject).to receive(:await_network_reconnect).at_least(:once)
|
77
|
-
subject.push(message)
|
78
|
-
sleep 0.1 # Await results
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
context "when an unknown error occurs" do
|
83
|
-
before { allow(::ActionSubscriber::Publisher).to receive(:publish).and_raise(ArgumentError) }
|
84
|
-
|
85
|
-
it "kills the consumer" do
|
86
|
-
consumer = subject.consumer
|
87
|
-
expect(consumer).to be_alive
|
88
|
-
subject.push(message)
|
89
|
-
sleep 0.1 # Await results
|
90
|
-
expect(consumer).to_not be_alive
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
describe "#push" do
|
96
|
-
after { ::ActionSubscriber.configuration.async_publisher_max_queue_size = 1000 }
|
97
|
-
after { ::ActionSubscriber.configuration.async_publisher_drop_messages_when_queue_full = false }
|
98
|
-
|
99
|
-
context "when the queue has room" do
|
100
|
-
before { allow(::Queue).to receive(:new).and_return(mock_queue) }
|
101
|
-
|
102
|
-
it "successfully adds to the queue" do
|
103
|
-
expect(mock_queue).to receive(:push).with(message)
|
104
|
-
subject.push(message)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
context "when the queue is full" do
|
109
|
-
before { ::ActionSubscriber.configuration.async_publisher_max_queue_size = -1 }
|
110
|
-
|
111
|
-
context "and we're dropping messages" do
|
112
|
-
before { ::ActionSubscriber.configuration.async_publisher_drop_messages_when_queue_full = true }
|
113
|
-
|
114
|
-
it "adding to the queue should not raise an error" do
|
115
|
-
expect { subject.push(message) }.to_not raise_error
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
context "and we're not dropping messages" do
|
120
|
-
before { ::ActionSubscriber.configuration.async_publisher_drop_messages_when_queue_full = false }
|
121
|
-
|
122
|
-
it "adding to the queue should raise error back to caller" do
|
123
|
-
expect { subject.push(message) }.to raise_error(described_class::UnableToPersistMessageError)
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
describe "#size" do
|
130
|
-
it "can return the size of the queue" do
|
131
|
-
expect(subject.size).to eq(0)
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|