hutch 0.24.0 → 1.0.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 +5 -5
- data/.travis.yml +18 -13
- data/CHANGELOG.md +227 -4
- data/Gemfile +3 -3
- data/LICENSE +1 -0
- data/README.md +94 -94
- data/bin/ci/before_build.sh +20 -0
- data/bin/ci/install_on_debian.sh +17 -0
- data/hutch.gemspec +5 -5
- data/lib/hutch.rb +8 -4
- data/lib/hutch/broker.rb +37 -10
- data/lib/hutch/cli.rb +22 -11
- data/lib/hutch/config.rb +12 -0
- data/lib/hutch/consumer.rb +32 -2
- data/lib/hutch/error_handlers.rb +1 -1
- data/lib/hutch/error_handlers/airbrake.rb +20 -2
- data/lib/hutch/error_handlers/base.rb +15 -0
- data/lib/hutch/error_handlers/honeybadger.rb +28 -14
- data/lib/hutch/error_handlers/logger.rb +7 -2
- data/lib/hutch/error_handlers/rollbar.rb +28 -0
- data/lib/hutch/error_handlers/sentry.rb +9 -2
- data/lib/hutch/publisher.rb +1 -1
- data/lib/hutch/tracers.rb +0 -1
- data/lib/hutch/version.rb +1 -2
- data/lib/hutch/waiter.rb +1 -1
- data/lib/hutch/worker.rb +30 -1
- data/spec/hutch/broker_spec.rb +34 -0
- data/spec/hutch/cli_spec.rb +13 -0
- data/spec/hutch/consumer_spec.rb +82 -4
- data/spec/hutch/error_handlers/airbrake_spec.rb +19 -0
- data/spec/hutch/error_handlers/honeybadger_spec.rb +22 -1
- data/spec/hutch/error_handlers/logger_spec.rb +11 -0
- data/spec/hutch/error_handlers/rollbar_spec.rb +45 -0
- data/spec/hutch/error_handlers/sentry_spec.rb +15 -0
- data/spec/hutch/waiter_spec.rb +2 -2
- data/spec/hutch/worker_spec.rb +1 -1
- metadata +22 -17
- data/lib/hutch/error_handlers/opbeat.rb +0 -24
- data/lib/hutch/tracers/opbeat.rb +0 -37
- data/spec/hutch/error_handlers/opbeat_spec.rb +0 -22
- data/spec/tracers/opbeat_spec.rb +0 -44
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'hutch/logging'
|
2
|
+
require 'hutch/error_handlers/base'
|
2
3
|
|
3
4
|
module Hutch
|
4
5
|
module ErrorHandlers
|
5
|
-
class Logger
|
6
|
-
include Logging
|
6
|
+
class Logger < ErrorHandlers::Base
|
7
7
|
|
8
8
|
def handle(properties, payload, consumer, ex)
|
9
9
|
message_id = properties.message_id
|
@@ -12,6 +12,11 @@ module Hutch
|
|
12
12
|
logger.error "#{prefix} #{ex.class} - #{ex.message}"
|
13
13
|
logger.error (['backtrace:'] + ex.backtrace).join("\n")
|
14
14
|
end
|
15
|
+
|
16
|
+
def handle_setup_exception(ex)
|
17
|
+
logger.error "#{ex.class} - #{ex.message}"
|
18
|
+
logger.error (['backtrace:'] + ex.backtrace).join("\n")
|
19
|
+
end
|
15
20
|
end
|
16
21
|
end
|
17
22
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'hutch/logging'
|
2
|
+
require 'rollbar'
|
3
|
+
require 'hutch/error_handlers/base'
|
4
|
+
|
5
|
+
module Hutch
|
6
|
+
module ErrorHandlers
|
7
|
+
class Rollbar < Base
|
8
|
+
def handle(properties, payload, consumer, ex)
|
9
|
+
message_id = properties.message_id
|
10
|
+
prefix = "message(#{message_id || '-'}):"
|
11
|
+
logger.error "#{prefix} Logging event to Rollbar"
|
12
|
+
logger.error "#{prefix} #{ex.class} - #{ex.message}"
|
13
|
+
|
14
|
+
::Rollbar.error(ex,
|
15
|
+
payload: payload,
|
16
|
+
consumer: consumer
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
def handle_setup_exception(ex)
|
21
|
+
logger.error "Logging setup exception to Rollbar"
|
22
|
+
logger.error "#{ex.class} - #{ex.message}"
|
23
|
+
|
24
|
+
::Rollbar.error(ex)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
require 'hutch/logging'
|
2
2
|
require 'raven'
|
3
|
+
require 'hutch/error_handlers/base'
|
3
4
|
|
4
5
|
module Hutch
|
5
6
|
module ErrorHandlers
|
6
|
-
class Sentry
|
7
|
-
include Logging
|
7
|
+
class Sentry < Base
|
8
8
|
|
9
9
|
def initialize
|
10
10
|
unless Raven.respond_to?(:capture_exception)
|
@@ -19,6 +19,13 @@ module Hutch
|
|
19
19
|
logger.error "#{prefix} #{ex.class} - #{ex.message}"
|
20
20
|
Raven.capture_exception(ex, extra: { payload: payload })
|
21
21
|
end
|
22
|
+
|
23
|
+
def handle_setup_exception(ex)
|
24
|
+
logger.error "Logging setup exception to Sentry"
|
25
|
+
logger.error "#{ex.class} - #{ex.message}"
|
26
|
+
Raven.capture_exception(ex)
|
27
|
+
end
|
28
|
+
|
22
29
|
end
|
23
30
|
end
|
24
31
|
end
|
data/lib/hutch/publisher.rb
CHANGED
data/lib/hutch/tracers.rb
CHANGED
data/lib/hutch/version.rb
CHANGED
data/lib/hutch/waiter.rb
CHANGED
data/lib/hutch/worker.rb
CHANGED
@@ -36,12 +36,17 @@ module Hutch
|
|
36
36
|
# Set up the queues for each of the worker's consumers.
|
37
37
|
def setup_queues
|
38
38
|
logger.info 'setting up queues'
|
39
|
-
@consumers.
|
39
|
+
vetted = @consumers.reject { |c| group_configured? && group_restricted?(c) }
|
40
|
+
vetted.each do |c|
|
41
|
+
setup_queue(c)
|
42
|
+
end
|
40
43
|
end
|
41
44
|
|
42
45
|
# Bind a consumer's routing keys to its queue, and set up a subscription to
|
43
46
|
# receive messages sent to the queue.
|
44
47
|
def setup_queue(consumer)
|
48
|
+
logger.info "setting up queue: #{consumer.get_queue_name}"
|
49
|
+
|
45
50
|
queue = @broker.queue(consumer.get_queue_name, consumer.get_arguments)
|
46
51
|
@broker.bind_queue(queue, consumer.routing_keys)
|
47
52
|
|
@@ -103,6 +108,30 @@ module Hutch
|
|
103
108
|
|
104
109
|
private
|
105
110
|
|
111
|
+
def group_configured?
|
112
|
+
if group.present? && consumer_groups.blank?
|
113
|
+
logger.info 'Consumer groups are blank'
|
114
|
+
end
|
115
|
+
group.present?
|
116
|
+
end
|
117
|
+
|
118
|
+
def group_restricted?(consumer)
|
119
|
+
consumers_to_load = consumer_groups[group]
|
120
|
+
if consumers_to_load
|
121
|
+
!consumers_to_load.include?(consumer.name)
|
122
|
+
else
|
123
|
+
true
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def group
|
128
|
+
Hutch::Config[:group]
|
129
|
+
end
|
130
|
+
|
131
|
+
def consumer_groups
|
132
|
+
Hutch::Config[:consumer_groups]
|
133
|
+
end
|
134
|
+
|
106
135
|
attr_accessor :setup_procs
|
107
136
|
|
108
137
|
def unique_consumer_tag
|
data/spec/hutch/broker_spec.rb
CHANGED
@@ -92,6 +92,40 @@ describe Hutch::Broker do
|
|
92
92
|
|
93
93
|
connection.close
|
94
94
|
end
|
95
|
+
|
96
|
+
context 'when configured with a URI' do
|
97
|
+
context 'which specifies the port' do
|
98
|
+
before { config[:uri] = 'amqp://guest:guest@127.0.0.1:5672/' }
|
99
|
+
|
100
|
+
it 'successfully connects' do
|
101
|
+
c = broker.open_connection
|
102
|
+
expect(c).to be_open
|
103
|
+
c.close
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context 'which does not specify port and uses the amqp scheme' do
|
108
|
+
before { config[:uri] = 'amqp://guest:guest@127.0.0.1/' }
|
109
|
+
|
110
|
+
it 'successfully connects' do
|
111
|
+
c = broker.open_connection
|
112
|
+
expect(c).to be_open
|
113
|
+
c.close
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context 'which specifies the amqps scheme' do
|
118
|
+
before { config[:uri] = 'amqps://guest:guest@127.0.0.1/' }
|
119
|
+
|
120
|
+
it 'utilises TLS' do
|
121
|
+
expect(Hutch::Adapter).to receive(:new).with(
|
122
|
+
hash_including(tls: true, port: 5671)
|
123
|
+
).and_return(instance_double('Hutch::Adapter', start: nil))
|
124
|
+
|
125
|
+
broker.open_connection
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
95
129
|
end
|
96
130
|
|
97
131
|
describe '#open_connection!' do
|
data/spec/hutch/cli_spec.rb
CHANGED
@@ -4,6 +4,19 @@ require 'tempfile'
|
|
4
4
|
describe Hutch::CLI do
|
5
5
|
let(:cli) { Hutch::CLI.new }
|
6
6
|
|
7
|
+
describe "#start_work_loop" do
|
8
|
+
context "connection error during setup" do
|
9
|
+
let(:error) { Hutch::ConnectionError.new }
|
10
|
+
it "gets reported using error handlers" do
|
11
|
+
allow(Hutch).to receive(:connect).and_raise(error)
|
12
|
+
Hutch::Config[:error_handlers].each do |backend|
|
13
|
+
expect(backend).to receive(:handle_setup_exception).with(error)
|
14
|
+
end
|
15
|
+
cli.start_work_loop
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
7
20
|
describe "#parse_options" do
|
8
21
|
context "--config" do
|
9
22
|
context "when the config file does not exist" do
|
data/spec/hutch/consumer_spec.rb
CHANGED
@@ -28,6 +28,32 @@ describe Hutch::Consumer do
|
|
28
28
|
ComplexConsumer
|
29
29
|
end
|
30
30
|
|
31
|
+
let(:consumer_using_quorum_queue) do
|
32
|
+
unless defined? ConsumerUsingQuorumQueue
|
33
|
+
class ConsumerUsingQuorumQueue
|
34
|
+
include Hutch::Consumer
|
35
|
+
consume 'hutch.test1'
|
36
|
+
arguments foo: :bar
|
37
|
+
|
38
|
+
quorum_queue
|
39
|
+
end
|
40
|
+
end
|
41
|
+
ConsumerUsingQuorumQueue
|
42
|
+
end
|
43
|
+
|
44
|
+
let(:consumer_using_classic_queue) do
|
45
|
+
unless defined? ConsumerUsingLazyQueue
|
46
|
+
class ConsumerUsingLazyQueue
|
47
|
+
include Hutch::Consumer
|
48
|
+
consume 'hutch.test1'
|
49
|
+
arguments foo: :bar
|
50
|
+
lazy_queue
|
51
|
+
classic_queue
|
52
|
+
end
|
53
|
+
end
|
54
|
+
ConsumerUsingLazyQueue
|
55
|
+
end
|
56
|
+
|
31
57
|
describe 'module inclusion' do
|
32
58
|
it 'registers the class as a consumer' do
|
33
59
|
expect(Hutch).to receive(:register_consumer) do |klass|
|
@@ -71,6 +97,43 @@ describe Hutch::Consumer do
|
|
71
97
|
end
|
72
98
|
end
|
73
99
|
|
100
|
+
describe 'default queue mode' do
|
101
|
+
it 'does not specify any mode by default' do
|
102
|
+
expect(simple_consumer.queue_mode).to eq(nil)
|
103
|
+
expect(simple_consumer.queue_type).to eq(nil)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe '.lazy_queue' do
|
108
|
+
context 'when queue mode has been set explicitly to lazy' do
|
109
|
+
it 'sets queue mode to lazy' do
|
110
|
+
expect(consumer_using_classic_queue.queue_mode).to eq('lazy')
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe '.classic_queue' do
|
116
|
+
context 'when queue type has been set explicitly to classic' do
|
117
|
+
it 'sets queue type to classic' do
|
118
|
+
expect(consumer_using_classic_queue.queue_type).to eq('classic')
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe '.quorum_queue' do
|
124
|
+
context 'when queue type has been set explicitly to quorum' do
|
125
|
+
it 'sets queue type to quorum' do
|
126
|
+
expect(consumer_using_quorum_queue.queue_type).to eq('quorum')
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'accepts initial group size as an option' do
|
130
|
+
consumer = simple_consumer
|
131
|
+
expect { consumer.quorum_queue(initial_group_size: 3) }
|
132
|
+
.to change { consumer.initial_group_size }.to(3)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
74
137
|
describe '.arguments' do
|
75
138
|
let(:args) { { foo: :bar} }
|
76
139
|
|
@@ -82,15 +145,30 @@ describe Hutch::Consumer do
|
|
82
145
|
end
|
83
146
|
|
84
147
|
describe '.get_arguments' do
|
85
|
-
|
86
148
|
context 'when defined' do
|
87
|
-
it { expect(complex_consumer.get_arguments).to
|
149
|
+
it { expect(complex_consumer.get_arguments).to include(foo: :bar) }
|
88
150
|
end
|
89
151
|
|
90
|
-
context 'when
|
91
|
-
it
|
152
|
+
context 'when queue is lazy' do
|
153
|
+
it 'has the x-queue-mode argument set to lazy' do
|
154
|
+
expect(consumer_using_classic_queue.get_arguments['x-queue-mode'])
|
155
|
+
.to eq('lazy')
|
156
|
+
end
|
92
157
|
end
|
93
158
|
|
159
|
+
context "when queue's type is quorum" do
|
160
|
+
let(:arguments) { consumer_using_quorum_queue.get_arguments }
|
161
|
+
it 'has the x-queue-type argument set to quorum' do
|
162
|
+
expect(arguments['x-queue-type']).to eq('quorum')
|
163
|
+
expect(arguments).to_not have_key('x-quorum-initial-group-size')
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'has the x-quorum-initial-group-size argument set to quorum' do
|
167
|
+
consumer_using_quorum_queue.quorum_queue(initial_group_size: 5)
|
168
|
+
expect(arguments['x-queue-type']).to eq('quorum')
|
169
|
+
expect(arguments['x-quorum-initial-group-size']).to eq(5)
|
170
|
+
end
|
171
|
+
end
|
94
172
|
end
|
95
173
|
|
96
174
|
describe '.get_queue_name' do
|
@@ -27,4 +27,23 @@ describe Hutch::ErrorHandlers::Airbrake do
|
|
27
27
|
error_handler.handle(properties, payload, consumer, ex)
|
28
28
|
end
|
29
29
|
end
|
30
|
+
|
31
|
+
describe '#handle_setup_exception' do
|
32
|
+
let(:error) do
|
33
|
+
begin
|
34
|
+
raise "Stuff went wrong"
|
35
|
+
rescue RuntimeError => err
|
36
|
+
err
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it "logs the error to Airbrake" do
|
41
|
+
ex = error
|
42
|
+
message = {
|
43
|
+
cgi_data: ENV.to_hash,
|
44
|
+
}
|
45
|
+
expect(::Airbrake).to receive(:notify).with(ex, message)
|
46
|
+
error_handler.handle_setup_exception(ex)
|
47
|
+
end
|
48
|
+
end
|
30
49
|
end
|
@@ -30,8 +30,29 @@ describe Hutch::ErrorHandlers::Honeybadger do
|
|
30
30
|
:payload => payload
|
31
31
|
}
|
32
32
|
}
|
33
|
-
expect(
|
33
|
+
expect(error_handler).to receive(:notify_honeybadger).with(message)
|
34
34
|
error_handler.handle(properties, payload, consumer, ex)
|
35
35
|
end
|
36
36
|
end
|
37
|
+
|
38
|
+
describe '#handle_setup_exception' do
|
39
|
+
let(:error) do
|
40
|
+
begin
|
41
|
+
raise "Stuff went wrong during setup"
|
42
|
+
rescue RuntimeError => err
|
43
|
+
err
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it "logs the error to Honeybadger" do
|
48
|
+
ex = error
|
49
|
+
message = {
|
50
|
+
:error_class => ex.class.name,
|
51
|
+
:error_message => "#{ ex.class.name }: #{ ex.message }",
|
52
|
+
:backtrace => ex.backtrace,
|
53
|
+
}
|
54
|
+
expect(error_handler).to receive(:notify_honeybadger).with(message)
|
55
|
+
error_handler.handle_setup_exception(ex)
|
56
|
+
end
|
57
|
+
end
|
37
58
|
end
|
@@ -14,4 +14,15 @@ describe Hutch::ErrorHandlers::Logger do
|
|
14
14
|
error_handler.handle(properties, payload, double, error)
|
15
15
|
end
|
16
16
|
end
|
17
|
+
|
18
|
+
describe '#handle_setup_exception' do
|
19
|
+
let(:error) { double(message: "Stuff went wrong during setup",
|
20
|
+
class: "RuntimeError",
|
21
|
+
backtrace: ["line 1", "line 2"]) }
|
22
|
+
|
23
|
+
it "logs two separate lines" do
|
24
|
+
expect(Hutch::Logging.logger).to receive(:error).exactly(2).times
|
25
|
+
error_handler.handle_setup_exception(error)
|
26
|
+
end
|
27
|
+
end
|
17
28
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Hutch::ErrorHandlers::Rollbar do
|
4
|
+
let(:error_handler) { Hutch::ErrorHandlers::Rollbar.new }
|
5
|
+
|
6
|
+
describe '#handle' do
|
7
|
+
let(:error) do
|
8
|
+
begin
|
9
|
+
raise "Stuff went wrong"
|
10
|
+
rescue RuntimeError => err
|
11
|
+
err
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it "logs the error to Rollbar" do
|
16
|
+
message_id = "1"
|
17
|
+
properties = OpenStruct.new(message_id: message_id)
|
18
|
+
payload = "{}"
|
19
|
+
consumer = double
|
20
|
+
ex = error
|
21
|
+
message = {
|
22
|
+
payload: payload,
|
23
|
+
consumer: consumer
|
24
|
+
}
|
25
|
+
expect(::Rollbar).to receive(:error).with(ex, message)
|
26
|
+
error_handler.handle(properties, payload, consumer, ex)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#handle_setup_exception' do
|
31
|
+
let(:error) do
|
32
|
+
begin
|
33
|
+
raise "Stuff went wrong"
|
34
|
+
rescue RuntimeError => err
|
35
|
+
err
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it "logs the error to Rollbar" do
|
40
|
+
ex = error
|
41
|
+
expect(::Rollbar).to receive(:error).with(ex)
|
42
|
+
error_handler.handle_setup_exception(ex)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|