action_subscriber 2.0.1-java → 2.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 939204017ecb3b17925a0ceca1442798b98ddcdc
4
- data.tar.gz: 1780324c82d3dac0a2f0d36d00bfaa724296782f
3
+ metadata.gz: a8a1a10bb43fef34f63038536e121540df818b14
4
+ data.tar.gz: 78e17fea12571a3c07037a7123f2e529ee1580a3
5
5
  SHA512:
6
- metadata.gz: 258b3dcf397203650f2fe7c5b6590ddc3cf5ce0c9e81d1352d3a50505fc58ffa9b0dbcb5ec16b929d3ae9bb41580e6c15ba993da71194873eb4104ab58f44ba1
7
- data.tar.gz: 9235bf4d8f54c8616ff77f958da778d04cd4a3f6271968a74f35245ad9fbf9a52c9b7cf1cf642e04dfd71a5e3a7ea8d586d7986f06a3fd6f6e1fc94ac2ab8e86
6
+ metadata.gz: a1392baccf77a3b65c695fcb1ff5234a1ba2ef38ec83f4400f43b617be6659f0b5b31d6348e95b84e6f89bf5279643d10bcae072c4023c0d94531d8d28108e5a
7
+ data.tar.gz: c55665bfb5d487f800251d50f3737e46143092c539b81b041ffb49d5f50adf7a5a2aaade0dabc7fe3bf659f20f070b53103097958d32cfee766ffee64f76baa6
@@ -23,11 +23,13 @@ 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"
29
30
  require "action_subscriber/threadpool"
30
31
  require "action_subscriber/base"
32
+ require "action_subscriber/uri"
31
33
 
32
34
  module ActionSubscriber
33
35
  ##
@@ -110,6 +112,9 @@ module ActionSubscriber
110
112
  # Initialize config object
111
113
  config
112
114
 
115
+ # Intialize async publisher adapter
116
+ ::ActionSubscriber::Publisher::Async.publisher_adapter
117
+
113
118
  ::ActiveSupport.run_load_hooks(:action_subscriber, Base)
114
119
 
115
120
  ##
@@ -135,5 +140,6 @@ end
135
140
  require "action_subscriber/railtie" if defined?(Rails)
136
141
 
137
142
  at_exit do
143
+ ::ActionSubscriber::Publisher::Async.publisher_adapter.shutdown!
138
144
  ::ActionSubscriber::RabbitConnection.publisher_disconnect!
139
145
  end
@@ -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,
@@ -8,17 +12,24 @@ module ActionSubscriber
8
12
  :host,
9
13
  :hosts,
10
14
  :mode,
15
+ :password,
11
16
  :pop_interval,
12
17
  :port,
13
18
  :prefetch,
14
19
  :publisher_confirms,
15
20
  :seconds_to_wait_for_graceful_shutdown,
21
+ :username,
16
22
  :threadpool_size,
17
23
  :timeout,
18
- :times_to_pop
24
+ :times_to_pop,
25
+ :virtual_host
19
26
 
20
27
  DEFAULTS = {
21
28
  :allow_low_priority_methods => false,
29
+ :async_publisher => 'memory',
30
+ :async_publisher_drop_messages_when_queue_full => false,
31
+ :async_publisher_max_queue_size => 1_000_000,
32
+ :async_publisher_supervisor_interval => 200, # in milliseconds
22
33
  :default_exchange => 'events',
23
34
  :heartbeat => 5,
24
35
  :host => 'localhost',
@@ -31,7 +42,10 @@ module ActionSubscriber
31
42
  :seconds_to_wait_for_graceful_shutdown => 30,
32
43
  :threadpool_size => 8,
33
44
  :timeout => 1,
34
- :times_to_pop => 8
45
+ :times_to_pop => 8,
46
+ :username => "guest",
47
+ :password => "guest",
48
+ :virtual_host => "/"
35
49
  }
36
50
 
37
51
  ##
@@ -81,6 +95,13 @@ module ActionSubscriber
81
95
  self.decoder.merge!(decoders)
82
96
  end
83
97
 
98
+ def connection_string=(url)
99
+ settings = ::ActionSubscriber::URI.parse_amqp_url(url)
100
+ settings.each do |key, value|
101
+ send("#{key}=", value)
102
+ end
103
+ end
104
+
84
105
  def hosts
85
106
  return @hosts if @hosts.size > 0
86
107
  [ host ]
@@ -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
@@ -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
@@ -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?)
@@ -61,12 +62,15 @@ module ActionSubscriber
61
62
 
62
63
  def self.connection_options
63
64
  {
65
+ :continuation_timeout => ::ActionSubscriber.configuration.timeout * 1_000.0, #convert sec to ms
64
66
  :heartbeat => ::ActionSubscriber.configuration.heartbeat,
65
67
  :hosts => ::ActionSubscriber.configuration.hosts,
68
+ :pass => ::ActionSubscriber.configuration.password,
66
69
  :port => ::ActionSubscriber.configuration.port,
67
- :continuation_timeout => ::ActionSubscriber.configuration.timeout * 1_000.0, #convert sec to ms
70
+ :user => ::ActionSubscriber.configuration.username,
71
+ :vhost => ::ActionSubscriber.configuration.virtual_host,
68
72
  :automatically_recover => true,
69
- :network_recovery_interval => 1,
73
+ :network_recovery_interval => NETWORK_RECOVERY_INTERVAL,
70
74
  :recover_from_connection_close => true,
71
75
  }
72
76
  end
@@ -0,0 +1,28 @@
1
+ # Taken and adapted from https://github.com/ruby-amqp/amq-protocol/blob/master/lib/amq/uri.rb
2
+ require "cgi"
3
+ require "uri"
4
+
5
+ module ActionSubscriber
6
+ class URI
7
+ AMQP_PORTS = {"amqp" => 5672, "amqps" => 5671}.freeze
8
+
9
+ def self.parse_amqp_url(connection_string)
10
+ uri = ::URI.parse(connection_string)
11
+ raise ArgumentError.new("Connection URI must use amqp or amqps schema (example: amqp://bus.megacorp.internal:5766), learn more at http://bit.ly/ks8MXK") unless %w{amqp amqps}.include?(uri.scheme)
12
+
13
+ opts = {}
14
+
15
+ opts[:username] = ::CGI::unescape(uri.user) if uri.user
16
+ opts[:password] = ::CGI::unescape(uri.password) if uri.password
17
+ opts[:host] = uri.host if uri.host
18
+ opts[:port] = uri.port || AMQP_PORTS[uri.scheme]
19
+
20
+ if uri.path =~ %r{^/(.*)}
21
+ raise ArgumentError.new("#{uri} has multiple-segment path; please percent-encode any slashes in the vhost name (e.g. /production => %2Fproduction). Learn more at http://bit.ly/amqp-gem-and-connection-uris") if $1.index('/')
22
+ opts[:virtual_host] = ::CGI::unescape($1)
23
+ end
24
+
25
+ opts
26
+ end
27
+ end
28
+ end
@@ -1,3 +1,3 @@
1
1
  module ActionSubscriber
2
- VERSION = "2.0.1"
2
+ VERSION = "2.1.0"
3
3
  end
@@ -1,6 +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.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) }
4
8
  specify { expect(subject.default_exchange).to eq("events") }
5
9
  specify { expect(subject.heartbeat).to eq(5) }
6
10
  specify { expect(subject.host).to eq("localhost") }
@@ -34,4 +38,15 @@ describe ::ActionSubscriber::Configuration do
34
38
  }.to raise_error(/The foo decoder was given with arity of 2/)
35
39
  end
36
40
  end
41
+
42
+ describe "connection_string" do
43
+ it "explodes the connection string into the corresponding settings" do
44
+ subject.connection_string = "amqp://user:pass@host:100/vhost"
45
+ expect(subject.username).to eq("user")
46
+ expect(subject.password).to eq("pass")
47
+ expect(subject.host).to eq("host")
48
+ expect(subject.port).to eq(100)
49
+ expect(subject.virtual_host).to eq("vhost")
50
+ end
51
+ end
37
52
  end
@@ -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
@@ -13,6 +13,7 @@ require 'support/user_subscriber'
13
13
  require 'action_subscriber/rspec'
14
14
 
15
15
  # Silence the Logger
16
+ $TESTING = true
16
17
  ::ActionSubscriber::Logging.initialize_logger(nil)
17
18
 
18
19
  RSpec.configure do |config|
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.1
4
+ version: 2.1.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-01-26 00:00:00.000000000 Z
15
+ date: 2016-02-08 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  requirement: !ruby/object:Gem::Requirement
@@ -213,6 +213,8 @@ files:
213
213
  - lib/action_subscriber/middleware/router.rb
214
214
  - lib/action_subscriber/middleware/runner.rb
215
215
  - lib/action_subscriber/publisher.rb
216
+ - lib/action_subscriber/publisher/async.rb
217
+ - lib/action_subscriber/publisher/async/in_memory_adapter.rb
216
218
  - lib/action_subscriber/rabbit_connection.rb
217
219
  - lib/action_subscriber/railtie.rb
218
220
  - lib/action_subscriber/route.rb
@@ -221,6 +223,7 @@ files:
221
223
  - lib/action_subscriber/rspec.rb
222
224
  - lib/action_subscriber/subscribable.rb
223
225
  - lib/action_subscriber/threadpool.rb
226
+ - lib/action_subscriber/uri.rb
224
227
  - lib/action_subscriber/version.rb
225
228
  - routing.md
226
229
  - spec/integration/around_filters_spec.rb
@@ -244,6 +247,8 @@ files:
244
247
  - spec/lib/action_subscriber/middleware/error_handler_spec.rb
245
248
  - spec/lib/action_subscriber/middleware/router_spec.rb
246
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
247
252
  - spec/lib/action_subscriber/publisher_spec.rb
248
253
  - spec/lib/action_subscriber/router_spec.rb
249
254
  - spec/lib/action_subscriber/subscribable_spec.rb
@@ -270,7 +275,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
270
275
  version: '0'
271
276
  requirements: []
272
277
  rubyforge_project:
273
- rubygems_version: 2.5.0
278
+ rubygems_version: 2.4.8
274
279
  signing_key:
275
280
  specification_version: 4
276
281
  summary: ActionSubscriber is a DSL that allows a rails app to consume messages from a RabbitMQ broker.
@@ -296,6 +301,8 @@ test_files:
296
301
  - spec/lib/action_subscriber/middleware/error_handler_spec.rb
297
302
  - spec/lib/action_subscriber/middleware/router_spec.rb
298
303
  - spec/lib/action_subscriber/middleware/runner_spec.rb
304
+ - spec/lib/action_subscriber/publisher/async/in_memory_adapter_spec.rb
305
+ - spec/lib/action_subscriber/publisher/async_spec.rb
299
306
  - spec/lib/action_subscriber/publisher_spec.rb
300
307
  - spec/lib/action_subscriber/router_spec.rb
301
308
  - spec/lib/action_subscriber/subscribable_spec.rb