action_subscriber 2.0.1 → 2.1.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/lib/action_subscriber/configuration.rb +8 -0
- data/lib/action_subscriber/publisher/async/in_memory_adapter.rb +153 -0
- data/lib/action_subscriber/publisher/async.rb +31 -0
- data/lib/action_subscriber/rabbit_connection.rb +2 -1
- data/lib/action_subscriber/version.rb +1 -1
- data/lib/action_subscriber.rb +5 -0
- data/spec/lib/action_subscriber/configuration_spec.rb +4 -1
- data/spec/lib/action_subscriber/publisher/async/in_memory_adapter_spec.rb +135 -0
- data/spec/lib/action_subscriber/publisher/async_spec.rb +40 -0
- data/spec/spec_helper.rb +1 -0
- metadata +11 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cdfd01dd3dd2055815f165b70bce923d36fe1db7
|
4
|
+
data.tar.gz: 261530f967fe4368afa58295344e1fe40ee70746
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 109f19c08d6975bca0af2df1ff70483ef8e3211d235e4c4767cba1d386c78085be51d021357ccc76f1d2f86564fa3a43c3500869ba690e970f5cc06a3032ed9e
|
7
|
+
data.tar.gz: 3646c5fe3efb28a73d98a3a8aa991dfeac31e71d7946b0549dc7e32610c30cd6914241e6775f867828729e3bb15c6fa15ba48be715a1b1a7bc30352acc6e160e
|
@@ -1,6 +1,10 @@
|
|
1
1
|
module ActionSubscriber
|
2
2
|
class Configuration
|
3
3
|
attr_accessor :allow_low_priority_methods,
|
4
|
+
:async_publisher,
|
5
|
+
:async_publisher_drop_messages_when_queue_full,
|
6
|
+
:async_publisher_max_queue_size,
|
7
|
+
:async_publisher_supervisor_interval,
|
4
8
|
:decoder,
|
5
9
|
:default_exchange,
|
6
10
|
:error_handler,
|
@@ -19,6 +23,10 @@ module ActionSubscriber
|
|
19
23
|
|
20
24
|
DEFAULTS = {
|
21
25
|
:allow_low_priority_methods => false,
|
26
|
+
:async_publisher => 'memory',
|
27
|
+
:async_publisher_drop_messages_when_queue_full => false,
|
28
|
+
:async_publisher_max_queue_size => 1_000_000,
|
29
|
+
:async_publisher_supervisor_interval => 200, # in milliseconds
|
22
30
|
:default_exchange => 'events',
|
23
31
|
:heartbeat => 5,
|
24
32
|
:host => 'localhost',
|
@@ -0,0 +1,153 @@
|
|
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
|
@@ -0,0 +1,31 @@
|
|
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
|
@@ -4,6 +4,7 @@ module ActionSubscriber
|
|
4
4
|
module RabbitConnection
|
5
5
|
SUBSCRIBER_CONNECTION_MUTEX = ::Mutex.new
|
6
6
|
PUBLISHER_CONNECTION_MUTEX = ::Mutex.new
|
7
|
+
NETWORK_RECOVERY_INTERVAL = 1.freeze
|
7
8
|
|
8
9
|
def self.publisher_connected?
|
9
10
|
publisher_connection.try(:connected?)
|
@@ -66,7 +67,7 @@ module ActionSubscriber
|
|
66
67
|
:port => ::ActionSubscriber.configuration.port,
|
67
68
|
:continuation_timeout => ::ActionSubscriber.configuration.timeout * 1_000.0, #convert sec to ms
|
68
69
|
:automatically_recover => true,
|
69
|
-
:network_recovery_interval =>
|
70
|
+
:network_recovery_interval => NETWORK_RECOVERY_INTERVAL,
|
70
71
|
:recover_from_connection_close => true,
|
71
72
|
}
|
72
73
|
end
|
data/lib/action_subscriber.rb
CHANGED
@@ -23,6 +23,7 @@ require "action_subscriber/bunny/subscriber"
|
|
23
23
|
require "action_subscriber/march_hare/subscriber"
|
24
24
|
require "action_subscriber/babou"
|
25
25
|
require "action_subscriber/publisher"
|
26
|
+
require "action_subscriber/publisher/async"
|
26
27
|
require "action_subscriber/route"
|
27
28
|
require "action_subscriber/route_set"
|
28
29
|
require "action_subscriber/router"
|
@@ -110,6 +111,9 @@ module ActionSubscriber
|
|
110
111
|
# Initialize config object
|
111
112
|
config
|
112
113
|
|
114
|
+
# Intialize async publisher adapter
|
115
|
+
::ActionSubscriber::Publisher::Async.publisher_adapter
|
116
|
+
|
113
117
|
::ActiveSupport.run_load_hooks(:action_subscriber, Base)
|
114
118
|
|
115
119
|
##
|
@@ -135,5 +139,6 @@ end
|
|
135
139
|
require "action_subscriber/railtie" if defined?(Rails)
|
136
140
|
|
137
141
|
at_exit do
|
142
|
+
::ActionSubscriber::Publisher::Async.publisher_adapter.shutdown!
|
138
143
|
::ActionSubscriber::RabbitConnection.publisher_disconnect!
|
139
144
|
end
|
@@ -1,7 +1,10 @@
|
|
1
1
|
describe ::ActionSubscriber::Configuration do
|
2
2
|
describe "default values" do
|
3
3
|
specify { expect(subject.allow_low_priority_methods).to eq(false) }
|
4
|
-
specify { expect(subject.
|
4
|
+
specify { expect(subject.async_publisher).to eq("memory") }
|
5
|
+
specify { expect(subject.async_publisher_drop_messages_when_queue_full).to eq(false) }
|
6
|
+
specify { expect(subject.async_publisher_max_queue_size).to eq(1_000_000) }
|
7
|
+
specify { expect(subject.async_publisher_supervisor_interval).to eq(200) }
|
5
8
|
specify { expect(subject.heartbeat).to eq(5) }
|
6
9
|
specify { expect(subject.host).to eq("localhost") }
|
7
10
|
specify { expect(subject.mode).to eq('subscribe') }
|
@@ -0,0 +1,135 @@
|
|
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
|
@@ -0,0 +1,40 @@
|
|
1
|
+
describe ::ActionSubscriber::Publisher::Async do
|
2
|
+
|
3
|
+
before { described_class.instance_variable_set(:@publisher_adapter, nil) }
|
4
|
+
after { ::ActionSubscriber.configuration.async_publisher = "memory" }
|
5
|
+
|
6
|
+
let(:mock_adapter) { double(:publish => nil) }
|
7
|
+
|
8
|
+
describe ".publish_async" do
|
9
|
+
before { allow(described_class).to receive(:publisher_adapter).and_return(mock_adapter) }
|
10
|
+
|
11
|
+
it "calls through the adapter" do
|
12
|
+
expect(mock_adapter).to receive(:publish).with("1", "2", "3", { "four" => "five" })
|
13
|
+
::ActionSubscriber::Publisher.publish_async("1", "2", "3", { "four" => "five" })
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "when an in-memory adapter is selected" do
|
18
|
+
before { ::ActionSubscriber.configuration.async_publisher = "memory" }
|
19
|
+
|
20
|
+
it "Creates an in-memory publisher" do
|
21
|
+
expect(described_class.publisher_adapter).to be_an(::ActionSubscriber::Publisher::Async::InMemoryAdapter)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "when an redis adapter is selected" do
|
26
|
+
before { ::ActionSubscriber.configuration.async_publisher = "redis" }
|
27
|
+
|
28
|
+
it "raises an error" do
|
29
|
+
expect { described_class.publisher_adapter }.to raise_error("Not yet implemented")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "when some random adapter is selected" do
|
34
|
+
before { ::ActionSubscriber.configuration.async_publisher = "yolo" }
|
35
|
+
|
36
|
+
it "raises an error" do
|
37
|
+
expect { described_class.publisher_adapter }.to raise_error("Unknown adapter 'yolo' provided")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/spec/spec_helper.rb
CHANGED
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: 2.0.
|
4
|
+
version: 2.1.0.pre1
|
5
5
|
platform: ruby
|
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-
|
15
|
+
date: 2016-02-04 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: activesupport
|
@@ -214,6 +214,8 @@ files:
|
|
214
214
|
- lib/action_subscriber/middleware/router.rb
|
215
215
|
- lib/action_subscriber/middleware/runner.rb
|
216
216
|
- lib/action_subscriber/publisher.rb
|
217
|
+
- lib/action_subscriber/publisher/async.rb
|
218
|
+
- lib/action_subscriber/publisher/async/in_memory_adapter.rb
|
217
219
|
- lib/action_subscriber/rabbit_connection.rb
|
218
220
|
- lib/action_subscriber/railtie.rb
|
219
221
|
- lib/action_subscriber/route.rb
|
@@ -245,6 +247,8 @@ files:
|
|
245
247
|
- spec/lib/action_subscriber/middleware/error_handler_spec.rb
|
246
248
|
- spec/lib/action_subscriber/middleware/router_spec.rb
|
247
249
|
- spec/lib/action_subscriber/middleware/runner_spec.rb
|
250
|
+
- spec/lib/action_subscriber/publisher/async/in_memory_adapter_spec.rb
|
251
|
+
- spec/lib/action_subscriber/publisher/async_spec.rb
|
248
252
|
- spec/lib/action_subscriber/publisher_spec.rb
|
249
253
|
- spec/lib/action_subscriber/router_spec.rb
|
250
254
|
- spec/lib/action_subscriber/subscribable_spec.rb
|
@@ -266,12 +270,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
266
270
|
version: '0'
|
267
271
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
268
272
|
requirements:
|
269
|
-
- - "
|
273
|
+
- - ">"
|
270
274
|
- !ruby/object:Gem::Version
|
271
|
-
version:
|
275
|
+
version: 1.3.1
|
272
276
|
requirements: []
|
273
277
|
rubyforge_project:
|
274
|
-
rubygems_version: 2.5
|
278
|
+
rubygems_version: 2.4.5
|
275
279
|
signing_key:
|
276
280
|
specification_version: 4
|
277
281
|
summary: ActionSubscriber is a DSL that allows a rails app to consume messages from
|
@@ -298,6 +302,8 @@ test_files:
|
|
298
302
|
- spec/lib/action_subscriber/middleware/error_handler_spec.rb
|
299
303
|
- spec/lib/action_subscriber/middleware/router_spec.rb
|
300
304
|
- 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
|
301
307
|
- spec/lib/action_subscriber/publisher_spec.rb
|
302
308
|
- spec/lib/action_subscriber/router_spec.rb
|
303
309
|
- spec/lib/action_subscriber/subscribable_spec.rb
|