action_subscriber 1.6.0 → 1.7.0.pre0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/bin/action_subscriber +2 -2
- data/lib/action_subscriber.rb +12 -7
- data/lib/action_subscriber/babou.rb +9 -4
- data/lib/action_subscriber/bunny/subscriber.rb +7 -4
- data/lib/action_subscriber/logging.rb +27 -0
- data/lib/action_subscriber/march_hare/subscriber.rb +7 -4
- data/lib/action_subscriber/middleware/env.rb +1 -1
- data/lib/action_subscriber/middleware/error_handler.rb +3 -0
- data/lib/action_subscriber/middleware/router.rb +4 -0
- data/lib/action_subscriber/route.rb +4 -2
- data/lib/action_subscriber/threadpool.rb +22 -9
- data/lib/action_subscriber/version.rb +1 -1
- data/spec/integration/around_filters_spec.rb +6 -4
- data/spec/integration/at_least_once_spec.rb +6 -4
- data/spec/integration/at_most_once_spec.rb +6 -4
- data/spec/integration/automatic_reconnect_spec.rb +7 -6
- data/spec/integration/basic_subscriber_spec.rb +9 -21
- data/spec/integration/custom_headers_spec.rb +5 -0
- data/spec/integration/decoding_payloads_spec.rb +7 -6
- data/spec/integration/inferred_routes_spec.rb +46 -0
- data/spec/integration/manual_acknowledgement_spec.rb +6 -3
- data/spec/integration/multiple_threadpools_spec.rb +29 -0
- data/spec/spec_helper.rb +1 -0
- metadata +10 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 06d750a3ce695babe3b26f24e06284e0461d0654
|
4
|
+
data.tar.gz: abdfb7fa508022788480938484238e044cd5b159
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 75831f62c6cc6652a8e4e99b4716af452e6dbe371bdb4c7057b5bca1c0fe4165a668db899205a79c622b5b7060abc07380951b3192d8f36894fc6099717c99d1
|
7
|
+
data.tar.gz: e55a1dcd87c163f673819bb3aeb670c561023f493e7c6e0ad527a418ca4a6cfb52ae700765830c5ba313fb6cdda593cacab2b5d3be6a692e8755f6cb6db36f9b
|
data/.travis.yml
CHANGED
data/bin/action_subscriber
CHANGED
@@ -26,10 +26,10 @@ module ActionSubscriber
|
|
26
26
|
require options[:app]
|
27
27
|
|
28
28
|
$0 = "Action Subscriber server #{object_id}"
|
29
|
-
|
29
|
+
::ActionSubscriber.logger.info "Loading configuration..."
|
30
30
|
|
31
31
|
::ActionSubscriber::Configuration.configure_from_yaml_and_cli(options)
|
32
|
-
|
32
|
+
::ActionSubscriber.logger.info "Starting server..."
|
33
33
|
|
34
34
|
case ::ActionSubscriber.configuration.mode
|
35
35
|
when /pop/i then
|
data/lib/action_subscriber.rb
CHANGED
@@ -14,6 +14,7 @@ require "action_subscriber/version"
|
|
14
14
|
require "action_subscriber/default_routing"
|
15
15
|
require "action_subscriber/dsl"
|
16
16
|
require "action_subscriber/configuration"
|
17
|
+
require "action_subscriber/logging"
|
17
18
|
require "action_subscriber/message_retry"
|
18
19
|
require "action_subscriber/middleware"
|
19
20
|
require "action_subscriber/rabbit_connection"
|
@@ -61,15 +62,19 @@ module ActionSubscriber
|
|
61
62
|
@route_set = RouteSet.new(routes)
|
62
63
|
end
|
63
64
|
|
65
|
+
def self.logger
|
66
|
+
::ActionSubscriber::Logging.logger
|
67
|
+
end
|
68
|
+
|
64
69
|
def self.print_subscriptions
|
65
|
-
|
70
|
+
logger.info configuration.inspect
|
66
71
|
route_set.routes.group_by(&:subscriber).each do |subscriber, routes|
|
67
|
-
|
72
|
+
logger.info subscriber.name
|
68
73
|
routes.each do |route|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
74
|
+
logger.info " -- method: #{route.action}"
|
75
|
+
logger.info " -- exchange: #{route.exchange}"
|
76
|
+
logger.info " -- queue: #{route.queue}"
|
77
|
+
logger.info " -- routing_key: #{route.routing_key}"
|
73
78
|
end
|
74
79
|
end
|
75
80
|
end
|
@@ -112,7 +117,7 @@ module ActionSubscriber
|
|
112
117
|
#
|
113
118
|
def self.route_set
|
114
119
|
@route_set ||= begin
|
115
|
-
|
120
|
+
logger.warn "DEPRECATION WARNING: We are inferring your routes by looking at your subscribers. This behavior is deprecated and will be removed in version 2.0. Please see the routing guide at https://github.com/mxenabled/action_subscriber/blob/master/routing.md"
|
116
121
|
RouteSet.new(self.send(:default_routes))
|
117
122
|
end
|
118
123
|
end
|
@@ -11,11 +11,11 @@ module ActionSubscriber
|
|
11
11
|
sleep_time = ::ActionSubscriber.configuration.pop_interval.to_i / 1000.0
|
12
12
|
|
13
13
|
::ActionSubscriber.start_queues
|
14
|
-
|
14
|
+
logger.info "Action Subscriber is popping messages every #{sleep_time} seconds."
|
15
15
|
|
16
16
|
# How often do we want the timer checking for new pops
|
17
17
|
# since we included an eager popper we decreased the
|
18
|
-
# default check interval to
|
18
|
+
# default check interval to 100m
|
19
19
|
while true
|
20
20
|
::ActionSubscriber.auto_pop! unless shutting_down?
|
21
21
|
sleep sleep_time
|
@@ -33,7 +33,7 @@ module ActionSubscriber
|
|
33
33
|
load_subscribers unless subscribers_loaded?
|
34
34
|
|
35
35
|
::ActionSubscriber.start_subscribers
|
36
|
-
|
36
|
+
logger.info "Action Subscriber connected"
|
37
37
|
|
38
38
|
while true
|
39
39
|
sleep 1.0 #just hang around waiting for messages
|
@@ -68,6 +68,10 @@ module ActionSubscriber
|
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
|
+
def self.logger
|
72
|
+
::ActionSubscriber::Logging.logger
|
73
|
+
end
|
74
|
+
|
71
75
|
def self.reload_active_record
|
72
76
|
if defined?(::ActiveRecord::Base) && !::ActiveRecord::Base.connected?
|
73
77
|
::ActiveRecord::Base.establish_connection
|
@@ -82,11 +86,12 @@ module ActionSubscriber
|
|
82
86
|
@shutting_down = true
|
83
87
|
::Thread.new do
|
84
88
|
::ActionSubscriber.stop_subscribers!
|
85
|
-
|
89
|
+
logger.info "stopped all subscribers"
|
86
90
|
end.join
|
87
91
|
end
|
88
92
|
|
89
93
|
def self.stop_server!
|
94
|
+
# this method is called from within a TRAP context so we can't use the logger
|
90
95
|
puts "Stopping server..."
|
91
96
|
wait_loops = 0
|
92
97
|
::ActionSubscriber::Babou.stop_receving_messages!
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module ActionSubscriber
|
2
2
|
module Bunny
|
3
3
|
module Subscriber
|
4
|
+
include ::ActionSubscriber::Logging
|
5
|
+
|
4
6
|
def bunny_consumers
|
5
7
|
@bunny_consumers ||= []
|
6
8
|
end
|
@@ -29,7 +31,7 @@ module ActionSubscriber
|
|
29
31
|
:queue => queue.name,
|
30
32
|
}
|
31
33
|
env = ::ActionSubscriber::Middleware::Env.new(route.subscriber, encoded_payload, properties)
|
32
|
-
enqueue_env(env)
|
34
|
+
enqueue_env(route.threadpool, env)
|
33
35
|
end
|
34
36
|
end
|
35
37
|
end
|
@@ -52,7 +54,7 @@ module ActionSubscriber
|
|
52
54
|
:queue => queue.name,
|
53
55
|
}
|
54
56
|
env = ::ActionSubscriber::Middleware::Env.new(route.subscriber, encoded_payload, properties)
|
55
|
-
enqueue_env(env)
|
57
|
+
enqueue_env(route.threadpool, env)
|
56
58
|
end
|
57
59
|
bunny_consumers << consumer
|
58
60
|
queue.subscribe_with(consumer)
|
@@ -61,8 +63,9 @@ module ActionSubscriber
|
|
61
63
|
|
62
64
|
private
|
63
65
|
|
64
|
-
def enqueue_env(env)
|
65
|
-
|
66
|
+
def enqueue_env(threadpool, env)
|
67
|
+
logger.info "RECEIVED #{env.message_id} from #{env.queue}"
|
68
|
+
threadpool.async(env) do |env|
|
66
69
|
::ActiveSupport::Notifications.instrument "process_event.action_subscriber", :subscriber => env.subscriber.to_s, :routing_key => env.routing_key do
|
67
70
|
::ActionSubscriber.config.middleware.call(env)
|
68
71
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# Taken from https://github.com/mperham/sidekiq/blob/7f882787e53d234042ff18099241403300a47585/lib/sidekiq/logging.rb
|
2
|
+
require 'time'
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
module ActionSubscriber
|
6
|
+
module Logging
|
7
|
+
def self.initialize_logger(log_target = STDOUT)
|
8
|
+
oldlogger = defined?(@logger) ? @logger : nil
|
9
|
+
@logger = Logger.new(log_target)
|
10
|
+
@logger.level = Logger::INFO
|
11
|
+
oldlogger.close if oldlogger && !$TESTING # don't want to close testing's STDOUT logging
|
12
|
+
@logger
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.logger
|
16
|
+
defined?(@logger) ? @logger : initialize_logger
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.logger=(log)
|
20
|
+
@logger = (log ? log : Logger.new('/dev/null'))
|
21
|
+
end
|
22
|
+
|
23
|
+
def logger
|
24
|
+
::ActionSubscriber::Logging.logger
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module ActionSubscriber
|
2
2
|
module MarchHare
|
3
3
|
module Subscriber
|
4
|
+
include ::ActionSubscriber::Logging
|
5
|
+
|
4
6
|
def cancel_consumers!
|
5
7
|
march_hare_consumers.each(&:cancel)
|
6
8
|
end
|
@@ -25,7 +27,7 @@ module ActionSubscriber
|
|
25
27
|
:queue => queue.name,
|
26
28
|
}
|
27
29
|
env = ::ActionSubscriber::Middleware::Env.new(route.subscriber, encoded_payload, properties)
|
28
|
-
enqueue_env(env)
|
30
|
+
enqueue_env(route.threadpool, env)
|
29
31
|
end
|
30
32
|
end
|
31
33
|
|
@@ -49,7 +51,7 @@ module ActionSubscriber
|
|
49
51
|
:queue => queue.name,
|
50
52
|
}
|
51
53
|
env = ::ActionSubscriber::Middleware::Env.new(route.subscriber, encoded_payload, properties)
|
52
|
-
enqueue_env(env)
|
54
|
+
enqueue_env(route.threadpool, env)
|
53
55
|
end
|
54
56
|
|
55
57
|
march_hare_consumers << consumer
|
@@ -62,8 +64,9 @@ module ActionSubscriber
|
|
62
64
|
|
63
65
|
private
|
64
66
|
|
65
|
-
def enqueue_env(env)
|
66
|
-
|
67
|
+
def enqueue_env(threadpool, env)
|
68
|
+
logger.info "RECEIVED #{env.message_id} from #{env.queue}"
|
69
|
+
threadpool.async(env) do |env|
|
67
70
|
::ActiveSupport::Notifications.instrument "process_event.action_subscriber", :subscriber => env.subscriber.to_s, :routing_key => env.routing_key do
|
68
71
|
::ActionSubscriber.config.middleware.call(env)
|
69
72
|
end
|
@@ -30,7 +30,7 @@ module ActionSubscriber
|
|
30
30
|
@encoded_payload = encoded_payload
|
31
31
|
@exchange = properties.fetch(:exchange)
|
32
32
|
@headers = properties.fetch(:headers) || {}
|
33
|
-
@message_id = properties.fetch(:message_id)
|
33
|
+
@message_id = properties.fetch(:message_id) || ::Random.new.bytes(3).unpack("H*")[0]
|
34
34
|
@queue = properties.fetch(:queue)
|
35
35
|
@routing_key = properties.fetch(:routing_key)
|
36
36
|
@subscriber = subscriber
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module ActionSubscriber
|
2
2
|
module Middleware
|
3
3
|
class ErrorHandler
|
4
|
+
include ::ActionSubscriber::Logging
|
5
|
+
|
4
6
|
def initialize(app)
|
5
7
|
@app = app
|
6
8
|
end
|
@@ -8,6 +10,7 @@ module ActionSubscriber
|
|
8
10
|
def call(env)
|
9
11
|
@app.call(env)
|
10
12
|
rescue => error
|
13
|
+
logger.error "FAILED #{env.message_id}"
|
11
14
|
::ActionSubscriber.configuration.error_handler.call(error, env.to_h)
|
12
15
|
end
|
13
16
|
end
|
@@ -1,12 +1,16 @@
|
|
1
1
|
module ActionSubscriber
|
2
2
|
module Middleware
|
3
3
|
class Router
|
4
|
+
include ::ActionSubscriber::Logging
|
5
|
+
|
4
6
|
def initialize(app)
|
5
7
|
@app = app
|
6
8
|
end
|
7
9
|
|
8
10
|
def call(env)
|
11
|
+
logger.info "START #{env.message_id} #{env.subscriber}##{env.action}"
|
9
12
|
env.subscriber.run_action_with_filters(env, env.action)
|
13
|
+
logger.info "FINISHED #{env.message_id}"
|
10
14
|
end
|
11
15
|
end
|
12
16
|
end
|
@@ -4,18 +4,20 @@ module ActionSubscriber
|
|
4
4
|
:action,
|
5
5
|
:exchange,
|
6
6
|
:prefetch,
|
7
|
+
:queue,
|
7
8
|
:routing_key,
|
8
9
|
:subscriber,
|
9
|
-
:
|
10
|
+
:threadpool
|
10
11
|
|
11
12
|
def initialize(attributes)
|
12
13
|
@acknowledgements = attributes.fetch(:acknowledgements)
|
13
14
|
@action = attributes.fetch(:action)
|
14
15
|
@exchange = attributes.fetch(:exchange).to_s
|
15
16
|
@prefetch = attributes.fetch(:prefetch) { ::ActionSubscriber.config.prefetch }
|
17
|
+
@queue = attributes.fetch(:queue)
|
16
18
|
@routing_key = attributes.fetch(:routing_key)
|
17
19
|
@subscriber = attributes.fetch(:subscriber)
|
18
|
-
@
|
20
|
+
@threadpool = attributes.fetch(:threadpool) { ::ActionSubscriber::Threadpool.pool(:default) }
|
19
21
|
end
|
20
22
|
|
21
23
|
def acknowledgements?
|
@@ -4,17 +4,29 @@ module ActionSubscriber
|
|
4
4
|
# Class Methods
|
5
5
|
#
|
6
6
|
def self.busy?
|
7
|
-
|
7
|
+
pools.any? do |_pool_name, pool|
|
8
|
+
pool.pool_size == pool.busy_size
|
9
|
+
end
|
8
10
|
end
|
9
11
|
|
10
|
-
def self.
|
11
|
-
|
12
|
+
def self.new_pool(name, pool_size = nil)
|
13
|
+
fail ArgumentError, "#{name} already exists as a threadpool" if pools.key?(name)
|
14
|
+
pool_size ||= ::ActionSubscriber.config.threadpool_size
|
15
|
+
pools[name] = ::Lifeguard::InfiniteThreadpool.new(
|
16
|
+
:pool_size => pool_size
|
17
|
+
)
|
12
18
|
end
|
13
19
|
|
14
|
-
def self.pool
|
15
|
-
|
16
|
-
|
17
|
-
|
20
|
+
def self.pool(which_pool = :default)
|
21
|
+
pools[which_pool]
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.pools
|
25
|
+
@pools ||= {
|
26
|
+
:default => ::Lifeguard::InfiniteThreadpool.new(
|
27
|
+
:pool_size => ::ActionSubscriber.config.threadpool_size
|
28
|
+
)
|
29
|
+
}
|
18
30
|
end
|
19
31
|
|
20
32
|
def self.ready?
|
@@ -22,8 +34,9 @@ module ActionSubscriber
|
|
22
34
|
end
|
23
35
|
|
24
36
|
def self.ready_size
|
25
|
-
|
26
|
-
|
37
|
+
pools.inject(0) do |total_ready, (_pool_name, pool)|
|
38
|
+
total_ready + [0, pool.pool_size - pool.busy_size].max
|
39
|
+
end
|
27
40
|
end
|
28
41
|
end
|
29
42
|
end
|
@@ -22,15 +22,17 @@ class InstaSubscriber < ActionSubscriber::Base
|
|
22
22
|
end
|
23
23
|
|
24
24
|
describe "subscriber filters", :integration => true do
|
25
|
-
let(:
|
25
|
+
let(:draw_routes) do
|
26
|
+
::ActionSubscriber.draw_routes do
|
27
|
+
default_routes_for InstaSubscriber
|
28
|
+
end
|
29
|
+
end
|
26
30
|
let(:subscriber) { InstaSubscriber }
|
27
31
|
|
28
32
|
it "runs multiple around filters" do
|
29
33
|
$messages = [] #testing the order of things
|
30
34
|
::ActionSubscriber.auto_subscribe!
|
31
|
-
|
32
|
-
exchange = channel.topic("events")
|
33
|
-
exchange.publish("hEY Guyz!", :routing_key => "insta.first")
|
35
|
+
::ActionSubscriber::Publisher.publish("insta.first", "hEY Guyz!", "events")
|
34
36
|
|
35
37
|
verify_expectation_within(1.0) do
|
36
38
|
expect($messages).to eq [:whisper_before, :yell_before, "hEY Guyz!", :yell_after, :whisper_after]
|
@@ -8,14 +8,16 @@ class GorbyPuffSubscriber < ActionSubscriber::Base
|
|
8
8
|
end
|
9
9
|
|
10
10
|
describe "at_least_once! mode", :integration => true do
|
11
|
-
let(:
|
11
|
+
let(:draw_routes) do
|
12
|
+
::ActionSubscriber.draw_routes do
|
13
|
+
default_routes_for GorbyPuffSubscriber
|
14
|
+
end
|
15
|
+
end
|
12
16
|
let(:subscriber) { GorbyPuffSubscriber }
|
13
17
|
|
14
18
|
it "retries a failed job until it succeeds" do
|
15
19
|
::ActionSubscriber.auto_subscribe!
|
16
|
-
|
17
|
-
exchange = channel.topic("events")
|
18
|
-
exchange.publish("GrumpFace", :routing_key => "gorby_puff.grumpy")
|
20
|
+
::ActionSubscriber::Publisher.publish("gorby_puff.grumpy", "GrumpFace", "events")
|
19
21
|
|
20
22
|
verify_expectation_within(2.0) do
|
21
23
|
expect($messages).to eq Set.new(["GrumpFace::0","GrumpFace::1","GrumpFace::2"])
|
@@ -8,14 +8,16 @@ class PokemonSubscriber < ActionSubscriber::Base
|
|
8
8
|
end
|
9
9
|
|
10
10
|
describe "at_most_once! mode", :integration => true do
|
11
|
-
let(:
|
11
|
+
let(:draw_routes) do
|
12
|
+
::ActionSubscriber.draw_routes do
|
13
|
+
default_routes_for PokemonSubscriber
|
14
|
+
end
|
15
|
+
end
|
12
16
|
let(:subscriber) { PokemonSubscriber }
|
13
17
|
|
14
18
|
it "does not retry a failed message" do
|
15
19
|
::ActionSubscriber.auto_subscribe!
|
16
|
-
|
17
|
-
exchange = channel.topic("events")
|
18
|
-
exchange.publish("All Pokemon have been caught", :routing_key => "pokemon.caught_em_all")
|
20
|
+
::ActionSubscriber::Publisher.publish("pokemon.caught_em_all", "All Pokemon have been caught", "events")
|
19
21
|
|
20
22
|
verify_expectation_within(1.0) do
|
21
23
|
expect($messages.size).to eq 1
|
@@ -8,14 +8,17 @@ end
|
|
8
8
|
|
9
9
|
describe "Automatically reconnect on connection failure", :integration => true, :slow => true do
|
10
10
|
let(:connection) { subscriber.connection }
|
11
|
+
let(:draw_routes) do
|
12
|
+
::ActionSubscriber.draw_routes do
|
13
|
+
default_routes_for GusSubscriber
|
14
|
+
end
|
15
|
+
end
|
11
16
|
let(:http_client) { RabbitMQ::HTTP::Client.new("http://127.0.0.1:15672") }
|
12
17
|
let(:subscriber) { GusSubscriber }
|
13
18
|
|
14
19
|
it "reconnects when a connection drops" do
|
15
20
|
::ActionSubscriber::auto_subscribe!
|
16
|
-
|
17
|
-
exchange = channel.topic("events")
|
18
|
-
exchange.publish("First", :routing_key => "gus.spoke")
|
21
|
+
::ActionSubscriber::Publisher.publish("gus.spoke", "First", "events")
|
19
22
|
verify_expectation_within(5.0) do
|
20
23
|
expect($messages).to eq(Set.new(["First"]))
|
21
24
|
end
|
@@ -26,9 +29,7 @@ describe "Automatically reconnect on connection failure", :integration => true,
|
|
26
29
|
expect(connection).to be_open
|
27
30
|
end
|
28
31
|
|
29
|
-
|
30
|
-
exchange = channel.topic("events")
|
31
|
-
exchange.publish("Second", :routing_key => "gus.spoke")
|
32
|
+
::ActionSubscriber::Publisher.publish("gus.spoke", "Second", "events")
|
32
33
|
verify_expectation_within(5.0) do
|
33
34
|
expect($messages).to eq(Set.new(["First", "Second"]))
|
34
35
|
end
|
@@ -1,32 +1,23 @@
|
|
1
1
|
class BasicPushSubscriber < ActionSubscriber::Base
|
2
|
-
publisher :greg
|
3
|
-
|
4
|
-
# queue => alice.greg.basic_push.booked
|
5
|
-
# routing_key => greg.basic_push.booked
|
6
2
|
def booked
|
7
3
|
$messages << payload
|
8
4
|
end
|
9
|
-
|
10
|
-
queue_for :cancelled, "basic.cancelled"
|
11
|
-
routing_key_for :cancelled, "basic.cancelled"
|
12
|
-
|
13
|
-
def cancelled
|
14
|
-
$messages << payload
|
15
|
-
end
|
16
5
|
end
|
17
6
|
|
18
7
|
describe "A Basic Subscriber", :integration => true do
|
19
|
-
let(:
|
20
|
-
|
8
|
+
let(:draw_routes) do
|
9
|
+
::ActionSubscriber.draw_routes do
|
10
|
+
route ::BasicPushSubscriber, :booked
|
11
|
+
end
|
12
|
+
end
|
21
13
|
|
22
14
|
context "ActionSubscriber.auto_pop!" do
|
23
15
|
it "routes messages to the right place" do
|
24
|
-
::ActionSubscriber::Publisher.publish("
|
25
|
-
::ActionSubscriber::Publisher.publish("basic.cancelled", "Ohai Cancelled", "events")
|
16
|
+
::ActionSubscriber::Publisher.publish("basic_push.booked", "Ohai Booked", "events")
|
26
17
|
|
27
18
|
verify_expectation_within(2.0) do
|
28
19
|
::ActionSubscriber.auto_pop!
|
29
|
-
expect($messages).to eq(Set.new(["Ohai Booked"
|
20
|
+
expect($messages).to eq(Set.new(["Ohai Booked"]))
|
30
21
|
end
|
31
22
|
end
|
32
23
|
end
|
@@ -34,13 +25,10 @@ describe "A Basic Subscriber", :integration => true do
|
|
34
25
|
context "ActionSubscriber.auto_subscribe!" do
|
35
26
|
it "routes messages to the right place" do
|
36
27
|
::ActionSubscriber.auto_subscribe!
|
37
|
-
|
38
|
-
exchange = channel.topic("events")
|
39
|
-
exchange.publish("Ohai Booked", :routing_key => "greg.basic_push.booked")
|
40
|
-
exchange.publish("Ohai Cancelled", :routing_key => "basic.cancelled")
|
28
|
+
::ActionSubscriber::Publisher.publish("basic_push.booked", "Ohai Booked", "events")
|
41
29
|
|
42
30
|
verify_expectation_within(2.0) do
|
43
|
-
expect($messages).to eq(Set.new(["Ohai Booked"
|
31
|
+
expect($messages).to eq(Set.new(["Ohai Booked"]))
|
44
32
|
end
|
45
33
|
end
|
46
34
|
end
|
@@ -7,6 +7,11 @@ class PrankSubscriber < ActionSubscriber::Base
|
|
7
7
|
end
|
8
8
|
|
9
9
|
describe "Custom Headers Are Published and Received", :integration => true do
|
10
|
+
let(:draw_routes) do
|
11
|
+
::ActionSubscriber.draw_routes do
|
12
|
+
default_routes_for PrankSubscriber
|
13
|
+
end
|
14
|
+
end
|
10
15
|
let(:headers) { { "Custom" => "content/header" } }
|
11
16
|
|
12
17
|
it "works for auto_pop!" do
|
@@ -10,14 +10,17 @@ end
|
|
10
10
|
|
11
11
|
describe "Payload Decoding", :integration => true do
|
12
12
|
let(:connection) { subscriber.connection }
|
13
|
+
let(:draw_routes) do
|
14
|
+
::ActionSubscriber.draw_routes do
|
15
|
+
default_routes_for TwitterSubscriber
|
16
|
+
end
|
17
|
+
end
|
13
18
|
let(:subscriber) { TwitterSubscriber }
|
14
19
|
let(:json_string) { '{"foo": "bar"}' }
|
15
20
|
|
16
21
|
it "decodes json by default" do
|
17
22
|
::ActionSubscriber.auto_subscribe!
|
18
|
-
|
19
|
-
exchange = channel.topic("events")
|
20
|
-
exchange.publish(json_string, :routing_key => "twitter.tweet", :content_type => "application/json")
|
23
|
+
::ActionSubscriber::Publisher.publish("twitter.tweet", json_string, "events", :content_type => "application/json")
|
21
24
|
|
22
25
|
verify_expectation_within(2.0) do
|
23
26
|
expect($messages).to eq Set.new([{
|
@@ -35,9 +38,7 @@ describe "Payload Decoding", :integration => true do
|
|
35
38
|
|
36
39
|
it "it decodes the payload using the custom decoder" do
|
37
40
|
::ActionSubscriber.auto_subscribe!
|
38
|
-
|
39
|
-
exchange = channel.topic("events")
|
40
|
-
exchange.publish(json_string, :routing_key => "twitter.tweet", :content_type => content_type)
|
41
|
+
::ActionSubscriber::Publisher.publish("twitter.tweet", json_string, "events", :content_type => content_type)
|
41
42
|
|
42
43
|
verify_expectation_within(2.0) do
|
43
44
|
expect($messages).to eq Set.new([{
|
@@ -0,0 +1,46 @@
|
|
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
|
+
it "registers the routes and sets up the queues" do
|
37
|
+
::ActionSubscriber.auto_subscribe!
|
38
|
+
::ActionSubscriber::Publisher.publish("kyle.inference.yo", "YO", "events")
|
39
|
+
::ActionSubscriber::Publisher.publish("other_routing_key.hey", "HEY", "events")
|
40
|
+
|
41
|
+
verify_expectation_within(2.0) do
|
42
|
+
expect($messages).to eq(Set.new(["YO","HEY"]))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -13,13 +13,16 @@ end
|
|
13
13
|
|
14
14
|
describe "Manual Message Acknowledgment", :integration => true do
|
15
15
|
let(:connection) { subscriber.connection }
|
16
|
+
let(:draw_routes) do
|
17
|
+
::ActionSubscriber.draw_routes do
|
18
|
+
default_routes_for BaconSubscriber
|
19
|
+
end
|
20
|
+
end
|
16
21
|
let(:subscriber) { BaconSubscriber }
|
17
22
|
|
18
23
|
it "retries rejected messages and stops retrying acknowledged messages" do
|
19
24
|
::ActionSubscriber.auto_subscribe!
|
20
|
-
|
21
|
-
exchange = channel.topic("events")
|
22
|
-
exchange.publish("BACON!", :routing_key => "bacon.served")
|
25
|
+
::ActionSubscriber::Publisher.publish("bacon.served", "BACON!", "events")
|
23
26
|
|
24
27
|
verify_expectation_within(2.0) do
|
25
28
|
expect($messages).to eq(Set.new(["BACON!::0", "BACON!::1", "BACON!::2"]))
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class DifferentThreadpoolsSubscriber < ActionSubscriber::Base
|
2
|
+
def one
|
3
|
+
$messages << payload
|
4
|
+
end
|
5
|
+
|
6
|
+
def two
|
7
|
+
$messages << payload
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "Separate Threadpools for Different Message", :integration => true do
|
12
|
+
let(:draw_routes) do
|
13
|
+
low_priority_threadpool = ::ActionSubscriber::Threadpool.new_pool(:low_priority, 1)
|
14
|
+
::ActionSubscriber.draw_routes do
|
15
|
+
route DifferentThreadpoolsSubscriber, :one
|
16
|
+
route DifferentThreadpoolsSubscriber, :two, :threadpool => low_priority_threadpool
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it "processes messages in separate threadpools based on the routes" do
|
21
|
+
::ActionSubscriber.auto_subscribe!
|
22
|
+
::ActionSubscriber::Publisher.publish("different_threadpools.one", "ONE", "events")
|
23
|
+
::ActionSubscriber::Publisher.publish("different_threadpools.two", "TWO", "events")
|
24
|
+
|
25
|
+
verify_expectation_within(2.0) do
|
26
|
+
expect($messages).to eq(Set.new(["ONE","TWO"]))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
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: 1.
|
4
|
+
version: 1.7.0.pre0
|
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: 2015-12-
|
15
|
+
date: 2015-12-23 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: activesupport
|
@@ -202,6 +202,7 @@ files:
|
|
202
202
|
- lib/action_subscriber/configuration.rb
|
203
203
|
- lib/action_subscriber/default_routing.rb
|
204
204
|
- lib/action_subscriber/dsl.rb
|
205
|
+
- lib/action_subscriber/logging.rb
|
205
206
|
- lib/action_subscriber/march_hare/subscriber.rb
|
206
207
|
- lib/action_subscriber/message_retry.rb
|
207
208
|
- lib/action_subscriber/middleware.rb
|
@@ -230,7 +231,9 @@ files:
|
|
230
231
|
- spec/integration/basic_subscriber_spec.rb
|
231
232
|
- spec/integration/custom_headers_spec.rb
|
232
233
|
- spec/integration/decoding_payloads_spec.rb
|
234
|
+
- spec/integration/inferred_routes_spec.rb
|
233
235
|
- spec/integration/manual_acknowledgement_spec.rb
|
236
|
+
- spec/integration/multiple_threadpools_spec.rb
|
234
237
|
- spec/lib/action_subscriber/base_spec.rb
|
235
238
|
- spec/lib/action_subscriber/configuration_spec.rb
|
236
239
|
- spec/lib/action_subscriber/dsl_spec.rb
|
@@ -262,12 +265,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
262
265
|
version: '0'
|
263
266
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
264
267
|
requirements:
|
265
|
-
- - "
|
268
|
+
- - ">"
|
266
269
|
- !ruby/object:Gem::Version
|
267
|
-
version:
|
270
|
+
version: 1.3.1
|
268
271
|
requirements: []
|
269
272
|
rubyforge_project:
|
270
|
-
rubygems_version: 2.
|
273
|
+
rubygems_version: 2.5.1
|
271
274
|
signing_key:
|
272
275
|
specification_version: 4
|
273
276
|
summary: ActionSubscriber is a DSL that allows a rails app to consume messages from
|
@@ -280,7 +283,9 @@ test_files:
|
|
280
283
|
- spec/integration/basic_subscriber_spec.rb
|
281
284
|
- spec/integration/custom_headers_spec.rb
|
282
285
|
- spec/integration/decoding_payloads_spec.rb
|
286
|
+
- spec/integration/inferred_routes_spec.rb
|
283
287
|
- spec/integration/manual_acknowledgement_spec.rb
|
288
|
+
- spec/integration/multiple_threadpools_spec.rb
|
284
289
|
- spec/lib/action_subscriber/base_spec.rb
|
285
290
|
- spec/lib/action_subscriber/configuration_spec.rb
|
286
291
|
- spec/lib/action_subscriber/dsl_spec.rb
|