action_subscriber 1.6.0 → 1.7.0.pre0
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 -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
|