ElmerFudd 0.0.31 → 0.1.0
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/.gitignore +1 -0
- data/ElmerFudd.gemspec +3 -2
- data/Gemfile +0 -1
- data/README.md +1 -1
- data/Rakefile +5 -4
- data/circleci.yml +4 -0
- data/lib/ElmerFudd.rb +2 -0
- data/lib/ElmerFudd/benchmark_filter.rb +38 -0
- data/lib/ElmerFudd/direct_handler.rb +1 -1
- data/lib/ElmerFudd/exception_notification_filter.rb +17 -0
- data/lib/ElmerFudd/publisher.rb +61 -42
- data/lib/ElmerFudd/version.rb +1 -1
- data/test/smoke/call_test.rb +54 -0
- data/test/smoke/cast_test.rb +80 -0
- data/test/smoke/event_test.rb +61 -0
- data/test/smoke/external_handlers_test.rb +51 -0
- data/test/test_helper.rb +65 -0
- data/test/unit/benchmark_filter_test.rb +35 -0
- metadata +53 -28
- data/.ruby-gemset +0 -1
- data/.ruby-version +0 -1
- data/spec/spec_helper.rb +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1f3b594d1565a291ef8f3ea7fd8974e7f5881710
|
4
|
+
data.tar.gz: 4437ba2cf870d5a76cbee31dec91dcdc1e5541d0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8487db7dbd04a30b7cda67f0a923cf7f2edd1d1cfbc810409a33412bb6fbb9b999050abf791232a3716ec4fbc2aa8915acfcdcb5d63cc4c6838f507541879a6f
|
7
|
+
data.tar.gz: 21f18bace52a65eaca2f72adc4b901b15f2c6d469fdb1879bcf0be1b1f7afcffc8282393d445c68ea3634276b57b1e0c7e6db02444d3b88409c24effea85b94a
|
data/.gitignore
CHANGED
data/ElmerFudd.gemspec
CHANGED
@@ -19,7 +19,8 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_dependency "bunny", '>= 1.6.3'
|
22
|
+
spec.add_dependency "connection_pool", '>= 2.2.0'
|
23
|
+
spec.add_development_dependency "rake", "~> 10.4"
|
22
24
|
spec.add_development_dependency "bundler", "~> 1.5"
|
23
|
-
spec.add_development_dependency "
|
24
|
-
spec.add_development_dependency "rspec"
|
25
|
+
spec.add_development_dependency "minitest", "~> 5.7"
|
25
26
|
end
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Be vewwy, vewwy quiet...I'm hunting wabbits! [](https://travis-ci.org/bonusboxme/ElmerFudd)
|
1
|
+
# Be vewwy, vewwy quiet...I'm hunting wabbits! [](https://travis-ci.org/bonusboxme/ElmerFudd) 
|
2
2
|
|
3
3
|

|
4
4
|
|
data/Rakefile
CHANGED
data/circleci.yml
ADDED
data/lib/ElmerFudd.rb
CHANGED
@@ -19,9 +19,11 @@ module ElmerFudd
|
|
19
19
|
|
20
20
|
require 'ElmerFudd/active_record_connection_pool_filter'
|
21
21
|
require 'ElmerFudd/airbrake_filter'
|
22
|
+
require 'ElmerFudd/exception_notification_filter'
|
22
23
|
require 'ElmerFudd/discard_return_value_filter'
|
23
24
|
require 'ElmerFudd/drop_failed_filter'
|
24
25
|
require 'ElmerFudd/json_filter'
|
25
26
|
require 'ElmerFudd/redirect_failed_filter'
|
26
27
|
require 'ElmerFudd/retry_filter'
|
28
|
+
require 'ElmerFudd/benchmark_filter'
|
27
29
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'benchmark'
|
2
|
+
|
3
|
+
module ElmerFudd
|
4
|
+
class BenchmarkFilter
|
5
|
+
include Filter
|
6
|
+
|
7
|
+
def initialize(printer: method(:default_printer),
|
8
|
+
benchmark: Benchmark)
|
9
|
+
@printer = printer
|
10
|
+
@benchmark = benchmark
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env, message, filters)
|
14
|
+
result = nil
|
15
|
+
exception = nil
|
16
|
+
|
17
|
+
bm = @benchmark.measure do
|
18
|
+
begin
|
19
|
+
result = call_next(env, message, filters)
|
20
|
+
rescue Exception => e
|
21
|
+
exception = e
|
22
|
+
end
|
23
|
+
end
|
24
|
+
@printer.call(bm, exception, message.route, env.logger)
|
25
|
+
exception.nil? ? result : raise(exception)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def default_printer(bm, exception, route, logger)
|
31
|
+
if exception.nil?
|
32
|
+
logger.info "ElmerFudd::Benchmark Queue: #{route.queue_name} | Success | Total CPU: #{bm.total} | Wall time: #{bm.real}"
|
33
|
+
else
|
34
|
+
logger.info "ElmerFudd::Benchmark Queue: #{route.queue_name} | Exception: #{exception.class.name} | Total CPU: #{bm.total} | Wall time: #{bm.real}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -32,7 +32,7 @@ module ElmerFudd
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def call(env, message)
|
35
|
-
env.logger.debug "ElmerFudd
|
35
|
+
env.logger.debug "ElmerFudd #{self.class.name}.call (#{object_id}) queue_name: #{@route.queue_name}, exchange_name: #{@route.exchange_name}, filters: #{filters_names}, message: #{message.payload}"
|
36
36
|
call_next(env, message, @filters + [@callback])
|
37
37
|
end
|
38
38
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ElmerFudd
|
2
|
+
class ExceptionNotificationFilter
|
3
|
+
extend Filter
|
4
|
+
def self.call(env, message, filters)
|
5
|
+
call_next(env, message, filters)
|
6
|
+
rescue Exception => e
|
7
|
+
ExceptionNotifier.notify_exception(e, data: {
|
8
|
+
payload: message.payload,
|
9
|
+
queue: message.route.queue_name,
|
10
|
+
exchange_name: message.route.exchange_name,
|
11
|
+
routing_key: message.delivery_info.routing_key,
|
12
|
+
matched_routing_key: message.route.routing_keys
|
13
|
+
})
|
14
|
+
raise
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/ElmerFudd/publisher.rb
CHANGED
@@ -1,49 +1,84 @@
|
|
1
|
+
require 'connection_pool'
|
2
|
+
|
1
3
|
module ElmerFudd
|
2
4
|
class Publisher
|
3
|
-
|
5
|
+
class Exchange
|
6
|
+
def initialize(connection)
|
7
|
+
@channel = connection.create_channel
|
8
|
+
@reply_channel = connection.create_channel
|
9
|
+
@direct = @channel.default_exchange
|
10
|
+
@topic_x = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :direct
|
14
|
+
|
15
|
+
def rpc_reply_queue
|
16
|
+
@rpc_reply_queue ||= @reply_channel.queue("", exclusive: true)
|
17
|
+
end
|
18
|
+
|
19
|
+
def cancel_reply_consumer(consumer_tag)
|
20
|
+
@reply_channel.consumers[consumer_tag].cancel
|
21
|
+
end
|
22
|
+
|
23
|
+
def topic(name)
|
24
|
+
@topic_x[name] ||= @channel.topic(name)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(connection, uuid_service: -> { rand.to_s }, logger: Logger.new($stdout),
|
29
|
+
max_threads: 4)
|
4
30
|
@connection = connection
|
5
31
|
@logger = logger
|
6
32
|
@uuid_service = uuid_service
|
7
|
-
@
|
33
|
+
@exchange = ConnectionPool.new(size: max_threads, timeout: 3) do
|
34
|
+
Exchange.new(connection)
|
35
|
+
end
|
8
36
|
end
|
9
37
|
|
10
38
|
def notify(topic_exchange, routing_key, payload)
|
11
|
-
@
|
12
|
-
|
13
|
-
|
39
|
+
@exchange.with do |exchange|
|
40
|
+
@logger.debug "ElmerFudd: NOTIFY - topic_exchange: #{topic_exchange}, routing_key: #{routing_key}, payload: #{payload}"
|
41
|
+
exchange.topic(topic_exchange).publish payload.to_s, routing_key: routing_key
|
42
|
+
end
|
14
43
|
nil
|
15
44
|
end
|
16
45
|
|
17
46
|
def cast(queue_name, payload)
|
18
|
-
@
|
19
|
-
|
47
|
+
@exchange.with do |exchange|
|
48
|
+
@logger.debug "ElmerFudd: CAST - queue_name: #{queue_name}, payload: #{payload}"
|
49
|
+
exchange.direct.publish(payload.to_s, routing_key: queue_name)
|
50
|
+
end
|
20
51
|
nil
|
21
52
|
end
|
22
53
|
|
23
54
|
def call(queue_name, payload, timeout: 10)
|
24
|
-
@
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
55
|
+
@exchange.with do |exchange|
|
56
|
+
begin
|
57
|
+
@logger.debug "ElmerFudd: CALL - queue_name: #{queue_name}, payload: #{payload}, timeout: #{timeout}"
|
58
|
+
mutex = Mutex.new
|
59
|
+
resource = ConditionVariable.new
|
60
|
+
correlation_id = @uuid_service.call
|
61
|
+
consumer_tag = @uuid_service.call
|
62
|
+
response = nil
|
30
63
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
64
|
+
Timeout.timeout(timeout) do
|
65
|
+
exchange.rpc_reply_queue.subscribe(manual_ack: false, block: false, consumer_tag: consumer_tag) do |delivery_info, properties, payload|
|
66
|
+
if properties[:correlation_id] == correlation_id
|
67
|
+
response = payload
|
68
|
+
mutex.synchronize { resource.signal }
|
69
|
+
end
|
70
|
+
end
|
38
71
|
|
39
|
-
|
40
|
-
|
72
|
+
exchange.direct.publish(payload.to_s, routing_key: queue_name, reply_to: exchange.rpc_reply_queue.name,
|
73
|
+
correlation_id: correlation_id)
|
41
74
|
|
42
|
-
|
43
|
-
|
75
|
+
mutex.synchronize { resource.wait(mutex) unless response }
|
76
|
+
response
|
77
|
+
end
|
78
|
+
ensure
|
79
|
+
exchange.cancel_reply_consumer(consumer_tag)
|
80
|
+
end
|
44
81
|
end
|
45
|
-
ensure
|
46
|
-
reply_channel.consumers[consumer_tag].cancel
|
47
82
|
end
|
48
83
|
|
49
84
|
private
|
@@ -53,21 +88,5 @@ module ElmerFudd
|
|
53
88
|
c.start unless c.connected?
|
54
89
|
end
|
55
90
|
end
|
56
|
-
|
57
|
-
def x
|
58
|
-
@x ||= channel.default_exchange
|
59
|
-
end
|
60
|
-
|
61
|
-
def channel
|
62
|
-
@channel ||= connection.create_channel
|
63
|
-
end
|
64
|
-
|
65
|
-
def reply_channel
|
66
|
-
@reply_channel ||= connection.create_channel
|
67
|
-
end
|
68
|
-
|
69
|
-
def rpc_reply_queue
|
70
|
-
@rpc_reply_queue ||= reply_channel.queue("", exclusive: true)
|
71
|
-
end
|
72
91
|
end
|
73
92
|
end
|
data/lib/ElmerFudd/version.rb
CHANGED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class CallTest < MiniTest::Test
|
4
|
+
include RabbitHelper
|
5
|
+
TEST_QUEUE = "test.ElmerFudd.call"
|
6
|
+
|
7
|
+
class TestWorker < ElmerFudd::Worker
|
8
|
+
default_filters ElmerFudd::JsonFilter
|
9
|
+
|
10
|
+
handle_call(Route(TEST_QUEUE)) do |_env, message|
|
11
|
+
raise "unexpected error" if message.payload["raise"]
|
12
|
+
if delay = message.payload["delay"]
|
13
|
+
sleep delay
|
14
|
+
end
|
15
|
+
|
16
|
+
message.payload["message"]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def setup
|
21
|
+
super
|
22
|
+
start_worker TestWorker
|
23
|
+
end
|
24
|
+
|
25
|
+
def teardown
|
26
|
+
remove_queue TEST_QUEUE
|
27
|
+
super
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_call_returns_the_value_from_worker
|
31
|
+
assert_equal({"result" => "hello"},
|
32
|
+
@publisher.call(TEST_QUEUE, message: "hello"))
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_call_timeouts_if_worker_time_outs
|
36
|
+
response = nil
|
37
|
+
assert_raises Timeout::Error do
|
38
|
+
# The default timeout is different and greater than 0
|
39
|
+
response = @publisher.call(TEST_QUEUE, {message: "hello", delay: 2},
|
40
|
+
timeout: 0.5)
|
41
|
+
assert_nil response
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_call_timeouts_if_worker_crashes
|
46
|
+
response = nil
|
47
|
+
assert_raises Timeout::Error do
|
48
|
+
# The default timeout is different and greater than 0
|
49
|
+
response = @publisher.call(TEST_QUEUE, {message: "hello", raise: true},
|
50
|
+
timeout: 0.5)
|
51
|
+
assert_nil response
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class CastTest < MiniTest::Test
|
4
|
+
include RabbitHelper
|
5
|
+
TEST_QUEUE = "test.ElmerFudd.cast"
|
6
|
+
|
7
|
+
class TestWorker < ElmerFudd::Worker
|
8
|
+
default_filters ElmerFudd::JsonFilter
|
9
|
+
|
10
|
+
handle_cast(Route(TEST_QUEUE)) do |_env, message|
|
11
|
+
raise "unexpected error" if message.payload["raise"]
|
12
|
+
if delay = message.payload["delay"]
|
13
|
+
sleep delay
|
14
|
+
end
|
15
|
+
|
16
|
+
$responses << message.payload["message"]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def teardown
|
21
|
+
remove_queue TEST_QUEUE
|
22
|
+
super
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_basic_cast
|
26
|
+
start_worker TestWorker
|
27
|
+
@publisher.cast TEST_QUEUE, message: "hello"
|
28
|
+
|
29
|
+
Timeout.timeout(0.5) do
|
30
|
+
assert "hello", $responses.pop
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_basic_cast_blocks_worker_if_unexpected_exception_occurs
|
35
|
+
start_worker TestWorker
|
36
|
+
@publisher.cast TEST_QUEUE, message: "hello", raise: true
|
37
|
+
@publisher.cast TEST_QUEUE, message: "hello"
|
38
|
+
|
39
|
+
assert_always { $responses.empty? }
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_workers_continues_if_concurency_greater_than_1
|
43
|
+
start_worker TestWorker, concurrency: 2
|
44
|
+
@publisher.cast TEST_QUEUE, message: "hello", raise: true
|
45
|
+
@publisher.cast TEST_QUEUE, message: "hello2"
|
46
|
+
|
47
|
+
Timeout.timeout(0.5) do
|
48
|
+
assert "hello2", $responses.pop
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_work_in_parallel_if_concurrency_greater_than_1
|
53
|
+
skip "TODO: investigate why it fails"
|
54
|
+
start_worker TestWorker, concurrency: 2
|
55
|
+
@publisher.cast TEST_QUEUE, message: "hello", delay: 0.5
|
56
|
+
@publisher.cast TEST_QUEUE, message: "hello2", delay: 0.5
|
57
|
+
|
58
|
+
result = []
|
59
|
+
Timeout.timeout(1) do
|
60
|
+
2.times { result << $responses.pop }
|
61
|
+
end rescue Timeout::Error fail "jobs did not execute in parallel"
|
62
|
+
|
63
|
+
assert_equal %w(hello hello2), result.sort
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_multiple_workers_on_same_connection_work_in_parallel
|
67
|
+
start_worker TestWorker, connection: (conn = get_new_connection)
|
68
|
+
start_worker TestWorker, connection: conn
|
69
|
+
|
70
|
+
@publisher.cast TEST_QUEUE, message: "hello", delay: 0.5
|
71
|
+
@publisher.cast TEST_QUEUE, message: "hello2", delay: 0.5
|
72
|
+
|
73
|
+
result = []
|
74
|
+
Timeout.timeout(1) do
|
75
|
+
2.times { result << $responses.pop }
|
76
|
+
end rescue Timeout::Error fail "jobs did not execute in parallel"
|
77
|
+
|
78
|
+
assert_equal %w(hello hello2), result.sort
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class EventTest < MiniTest::Test
|
4
|
+
include RabbitHelper
|
5
|
+
TEST_QUEUE_1 = "test.ElmerFudd.event.all"
|
6
|
+
TEST_QUEUE_2 = "test.ElmerFudd.event.high_prio"
|
7
|
+
TEST_QUEUE_3 = "test.ElmerFudd.event.another"
|
8
|
+
|
9
|
+
class TestWorker < ElmerFudd::Worker
|
10
|
+
default_filters ElmerFudd::JsonFilter
|
11
|
+
|
12
|
+
handle_event(Route(TEST_QUEUE_1, "x_topic" => "event.#")) do |_env, message|
|
13
|
+
$responses.push message.payload["message"]
|
14
|
+
end
|
15
|
+
|
16
|
+
handle_event(Route(TEST_QUEUE_2, "x_topic" => "event.high.*")) do |_env, message|
|
17
|
+
$high_prio_responses.push message.payload["message"]
|
18
|
+
end
|
19
|
+
|
20
|
+
handle_event(Route(TEST_QUEUE_3, "x_topic" => ["multi-event.one", "multi-event.two"])) do |_env, message|
|
21
|
+
$responses.push message.payload["message"]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def setup
|
26
|
+
super
|
27
|
+
$high_prio_responses = Queue.new
|
28
|
+
start_worker TestWorker
|
29
|
+
end
|
30
|
+
|
31
|
+
def teardown
|
32
|
+
get_new_connection.channel.topic("x_topic").delete
|
33
|
+
remove_queue TEST_QUEUE_1
|
34
|
+
remove_queue TEST_QUEUE_2
|
35
|
+
remove_queue TEST_QUEUE_3
|
36
|
+
super
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_notify_matches_event_name
|
40
|
+
@publisher.notify "x_topic", "event.some_event", message: "hello"
|
41
|
+
|
42
|
+
Timeout.timeout(0.5) { assert_equal "hello", $responses.pop }
|
43
|
+
assert_always { $high_prio_responses.empty? }
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_message_can_match_multiple_queues
|
47
|
+
@publisher.notify "x_topic", "event.high.some_event", message: "hello2"
|
48
|
+
|
49
|
+
Timeout.timeout(0.5) { assert_equal "hello2", $responses.pop }
|
50
|
+
Timeout.timeout(0.5) { assert_equal "hello2", $high_prio_responses.pop }
|
51
|
+
assert_always { $responses.empty? }
|
52
|
+
assert_always { $high_prio_responses.empty? }
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_listening_on_many_events_does_not_deliver_twice
|
56
|
+
@publisher.notify "x_topic", "multi-event.two", message: "foo"
|
57
|
+
Timeout.timeout(0.5) { assert_equal "foo", $responses.pop }
|
58
|
+
assert_always { $responses.empty? }
|
59
|
+
assert_always { $high_prio_responses.empty? }
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ExternalHandlersTest < MiniTest::Test
|
4
|
+
include RabbitHelper
|
5
|
+
TEST_QUEUE = "test.ElmerFudd.cast"
|
6
|
+
|
7
|
+
module Handler
|
8
|
+
extend self
|
9
|
+
def call(_env, message)
|
10
|
+
run(text: message.payload["text"])
|
11
|
+
end
|
12
|
+
|
13
|
+
def run(text:, **_ignore_rest_of_the_payload)
|
14
|
+
$responses.push text
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class TestWorker1 < ElmerFudd::Worker
|
19
|
+
default_filters ElmerFudd::JsonFilter
|
20
|
+
handle_cast(Route(TEST_QUEUE), handler: Handler)
|
21
|
+
end
|
22
|
+
|
23
|
+
class TestWorker2 < ElmerFudd::Worker
|
24
|
+
default_filters ElmerFudd::JsonFilter
|
25
|
+
handle_cast(Route(TEST_QUEUE),
|
26
|
+
handler: payload_as_kwargs(Handler.method(:run)))
|
27
|
+
end
|
28
|
+
|
29
|
+
def teardown
|
30
|
+
remove_queue TEST_QUEUE
|
31
|
+
super
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_external_handler
|
35
|
+
start_worker TestWorker1
|
36
|
+
@publisher.cast TEST_QUEUE, text: "hello"
|
37
|
+
|
38
|
+
Timeout.timeout(0.5) do
|
39
|
+
assert "hello", $responses.pop
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_payload_as_kwargs
|
44
|
+
start_worker TestWorker2
|
45
|
+
@publisher.cast TEST_QUEUE, text: "hello", ignored_param: true
|
46
|
+
|
47
|
+
Timeout.timeout(0.5) do
|
48
|
+
assert "hello", $responses.pop
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'ElmerFudd'
|
2
|
+
require 'minitest'
|
3
|
+
require 'minitest/unit'
|
4
|
+
require 'minitest/autorun'
|
5
|
+
require 'minitest/pride'
|
6
|
+
|
7
|
+
class NullLoger < Logger
|
8
|
+
def initialize(*args)
|
9
|
+
end
|
10
|
+
|
11
|
+
def add(*args, &block)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module RabbitHelper
|
16
|
+
def setup
|
17
|
+
super
|
18
|
+
@publisher = ElmerFudd::JsonPublisher.new(get_new_connection, logger: NullLoger.new)
|
19
|
+
$responses = Queue.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def teardown
|
23
|
+
sleep 0.1
|
24
|
+
rabbit_close_connections
|
25
|
+
super
|
26
|
+
end
|
27
|
+
|
28
|
+
def rabbitmq_url
|
29
|
+
ENV.fetch('RABBITMQ_URL', 'amqp://localhost:5672')
|
30
|
+
end
|
31
|
+
|
32
|
+
def get_new_connection(url: rabbitmq_url, auto_start: true)
|
33
|
+
Bunny.new(url, logger: NullLoger.new).tap do |connection|
|
34
|
+
connection.start if auto_start
|
35
|
+
(@rabbit_connections ||= []) << connection
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def remove_queue(queue_name)
|
40
|
+
conn = get_new_connection
|
41
|
+
channel = conn.channel
|
42
|
+
channel.queue(queue_name).delete
|
43
|
+
rescue Bunny::PreconditionFailed
|
44
|
+
channel = conn.channel
|
45
|
+
channel.queue(queue_name, durable: true).delete
|
46
|
+
end
|
47
|
+
|
48
|
+
def rabbit_close_connections
|
49
|
+
if @rabbit_connections
|
50
|
+
@rabbit_connections.each(&:close)
|
51
|
+
@rabbit_connections.clear
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def start_worker(worker_class, concurrency: 1, connection: get_new_connection)
|
56
|
+
worker_class.new(connection, concurrency: concurrency,
|
57
|
+
logger: NullLoger.new).tap(&:start)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def assert_always(timeout = 0.5, &condition)
|
62
|
+
Timeout.timeout(timeout) do
|
63
|
+
loop { assert condition.call; sleep timeout / 10.0 }
|
64
|
+
end rescue Timeout::Error
|
65
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class BenchmarkFilterTest < MiniTest::Test
|
4
|
+
class FakeLogger
|
5
|
+
attr_reader :logs
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@logs = Hash.new { |h, key| h[key] = [] }
|
9
|
+
end
|
10
|
+
|
11
|
+
def method_missing(log_level, message)
|
12
|
+
@logs[log_level.to_sym] << message
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def bm_filter(**kwargs)
|
17
|
+
ElmerFudd::BenchmarkFilter.new(**kwargs)
|
18
|
+
end
|
19
|
+
|
20
|
+
def env
|
21
|
+
Struct.new(:logger).new(@logger)
|
22
|
+
end
|
23
|
+
|
24
|
+
def setup
|
25
|
+
@logger = FakeLogger.new
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_measures_time_of_the_block
|
29
|
+
message = OpenStruct.new(route: OpenStruct.new(queue_name: "foo"))
|
30
|
+
ElmerFudd::BenchmarkFilter.new.call(env, message, [->(*){ sleep 1 }])
|
31
|
+
log_entry = @logger.logs[:info].first
|
32
|
+
assert_match /Queue: foo/, log_entry
|
33
|
+
assert_match /Wall time: 1\.\d+/, log_entry
|
34
|
+
end
|
35
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ElmerFudd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrzej Sliwa
|
@@ -9,64 +9,78 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2016-03-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bunny
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
|
-
- -
|
18
|
+
- - ">="
|
19
19
|
- !ruby/object:Gem::Version
|
20
20
|
version: 1.6.3
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
|
-
- -
|
25
|
+
- - ">="
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: 1.6.3
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
|
-
name:
|
29
|
+
name: connection_pool
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
|
-
- -
|
32
|
+
- - ">="
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version:
|
35
|
-
type: :
|
34
|
+
version: 2.2.0
|
35
|
+
type: :runtime
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
|
-
- -
|
39
|
+
- - ">="
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
-
version:
|
41
|
+
version: 2.2.0
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: rake
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
45
45
|
requirements:
|
46
|
-
- -
|
46
|
+
- - "~>"
|
47
47
|
- !ruby/object:Gem::Version
|
48
|
-
version: '
|
48
|
+
version: '10.4'
|
49
49
|
type: :development
|
50
50
|
prerelease: false
|
51
51
|
version_requirements: !ruby/object:Gem::Requirement
|
52
52
|
requirements:
|
53
|
-
- -
|
53
|
+
- - "~>"
|
54
54
|
- !ruby/object:Gem::Version
|
55
|
-
version: '
|
55
|
+
version: '10.4'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: bundler
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - "~>"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '1.5'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '1.5'
|
56
70
|
- !ruby/object:Gem::Dependency
|
57
|
-
name:
|
71
|
+
name: minitest
|
58
72
|
requirement: !ruby/object:Gem::Requirement
|
59
73
|
requirements:
|
60
|
-
- -
|
74
|
+
- - "~>"
|
61
75
|
- !ruby/object:Gem::Version
|
62
|
-
version: '
|
76
|
+
version: '5.7'
|
63
77
|
type: :development
|
64
78
|
prerelease: false
|
65
79
|
version_requirements: !ruby/object:Gem::Requirement
|
66
80
|
requirements:
|
67
|
-
- -
|
81
|
+
- - "~>"
|
68
82
|
- !ruby/object:Gem::Version
|
69
|
-
version: '
|
83
|
+
version: '5.7'
|
70
84
|
description: Be vewwy, vewwy quiet...I'm hunting wabbits!
|
71
85
|
email:
|
72
86
|
- andrzej.sliwa@i-tool.eu
|
@@ -75,22 +89,23 @@ executables: []
|
|
75
89
|
extensions: []
|
76
90
|
extra_rdoc_files: []
|
77
91
|
files:
|
78
|
-
- .gitignore
|
79
|
-
- .rspec
|
80
|
-
- .ruby-gemset
|
81
|
-
- .ruby-version
|
92
|
+
- ".gitignore"
|
93
|
+
- ".rspec"
|
82
94
|
- ElmerFudd.gemspec
|
83
95
|
- Gemfile
|
84
96
|
- LICENSE.txt
|
85
97
|
- README.md
|
86
98
|
- Rakefile
|
99
|
+
- circleci.yml
|
87
100
|
- elmer-fudd.jpg
|
88
101
|
- lib/ElmerFudd.rb
|
89
102
|
- lib/ElmerFudd/active_record_connection_pool_filter.rb
|
90
103
|
- lib/ElmerFudd/airbrake_filter.rb
|
104
|
+
- lib/ElmerFudd/benchmark_filter.rb
|
91
105
|
- lib/ElmerFudd/direct_handler.rb
|
92
106
|
- lib/ElmerFudd/discard_return_value_filter.rb
|
93
107
|
- lib/ElmerFudd/drop_failed_filter.rb
|
108
|
+
- lib/ElmerFudd/exception_notification_filter.rb
|
94
109
|
- lib/ElmerFudd/filter.rb
|
95
110
|
- lib/ElmerFudd/json_filter.rb
|
96
111
|
- lib/ElmerFudd/json_publisher.rb
|
@@ -102,7 +117,12 @@ files:
|
|
102
117
|
- lib/ElmerFudd/topic_handler.rb
|
103
118
|
- lib/ElmerFudd/version.rb
|
104
119
|
- lib/ElmerFudd/worker.rb
|
105
|
-
-
|
120
|
+
- test/smoke/call_test.rb
|
121
|
+
- test/smoke/cast_test.rb
|
122
|
+
- test/smoke/event_test.rb
|
123
|
+
- test/smoke/external_handlers_test.rb
|
124
|
+
- test/test_helper.rb
|
125
|
+
- test/unit/benchmark_filter_test.rb
|
106
126
|
homepage: https://github.com/bonusboxme/ElmerFudd
|
107
127
|
licenses:
|
108
128
|
- MIT
|
@@ -113,19 +133,24 @@ require_paths:
|
|
113
133
|
- lib
|
114
134
|
required_ruby_version: !ruby/object:Gem::Requirement
|
115
135
|
requirements:
|
116
|
-
- -
|
136
|
+
- - ">="
|
117
137
|
- !ruby/object:Gem::Version
|
118
138
|
version: '0'
|
119
139
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
140
|
requirements:
|
121
|
-
- -
|
141
|
+
- - ">="
|
122
142
|
- !ruby/object:Gem::Version
|
123
143
|
version: '0'
|
124
144
|
requirements: []
|
125
145
|
rubyforge_project:
|
126
|
-
rubygems_version: 2.4.
|
146
|
+
rubygems_version: 2.4.8
|
127
147
|
signing_key:
|
128
148
|
specification_version: 4
|
129
149
|
summary: RabbitMQ in OTP way
|
130
150
|
test_files:
|
131
|
-
-
|
151
|
+
- test/smoke/call_test.rb
|
152
|
+
- test/smoke/cast_test.rb
|
153
|
+
- test/smoke/event_test.rb
|
154
|
+
- test/smoke/external_handlers_test.rb
|
155
|
+
- test/test_helper.rb
|
156
|
+
- test/unit/benchmark_filter_test.rb
|
data/.ruby-gemset
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
ElmerFudd
|
data/.ruby-version
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
2.0.0
|
data/spec/spec_helper.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
-
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
-
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
|
-
# loaded once.
|
5
|
-
#
|
6
|
-
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
-
RSpec.configure do |config|
|
8
|
-
config.treat_symbols_as_metadata_keys_with_true_values = true
|
9
|
-
config.run_all_when_everything_filtered = true
|
10
|
-
config.filter_run :focus
|
11
|
-
|
12
|
-
# Run specs in random order to surface order dependencies. If you find an
|
13
|
-
# order dependency and want to debug it, you can fix the order by providing
|
14
|
-
# the seed, which is printed after each run.
|
15
|
-
# --seed 1234
|
16
|
-
config.order = 'random'
|
17
|
-
end
|