hutch 0.19.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/.travis.yml +11 -0
  4. data/CHANGELOG.md +438 -0
  5. data/Gemfile +22 -0
  6. data/Guardfile +5 -0
  7. data/LICENSE +22 -0
  8. data/README.md +317 -0
  9. data/Rakefile +14 -0
  10. data/bin/hutch +8 -0
  11. data/circle.yml +3 -0
  12. data/examples/consumer.rb +13 -0
  13. data/examples/producer.rb +10 -0
  14. data/hutch.gemspec +30 -0
  15. data/lib/hutch.rb +62 -0
  16. data/lib/hutch/adapter.rb +11 -0
  17. data/lib/hutch/adapters/bunny.rb +33 -0
  18. data/lib/hutch/adapters/march_hare.rb +37 -0
  19. data/lib/hutch/broker.rb +374 -0
  20. data/lib/hutch/cli.rb +205 -0
  21. data/lib/hutch/config.rb +125 -0
  22. data/lib/hutch/consumer.rb +75 -0
  23. data/lib/hutch/error_handlers.rb +8 -0
  24. data/lib/hutch/error_handlers/airbrake.rb +26 -0
  25. data/lib/hutch/error_handlers/honeybadger.rb +28 -0
  26. data/lib/hutch/error_handlers/logger.rb +16 -0
  27. data/lib/hutch/error_handlers/sentry.rb +23 -0
  28. data/lib/hutch/exceptions.rb +7 -0
  29. data/lib/hutch/logging.rb +32 -0
  30. data/lib/hutch/message.rb +31 -0
  31. data/lib/hutch/serializers/identity.rb +19 -0
  32. data/lib/hutch/serializers/json.rb +22 -0
  33. data/lib/hutch/tracers.rb +6 -0
  34. data/lib/hutch/tracers/newrelic.rb +19 -0
  35. data/lib/hutch/tracers/null_tracer.rb +15 -0
  36. data/lib/hutch/version.rb +4 -0
  37. data/lib/hutch/worker.rb +143 -0
  38. data/spec/hutch/broker_spec.rb +377 -0
  39. data/spec/hutch/cli_spec.rb +80 -0
  40. data/spec/hutch/config_spec.rb +126 -0
  41. data/spec/hutch/consumer_spec.rb +130 -0
  42. data/spec/hutch/error_handlers/airbrake_spec.rb +34 -0
  43. data/spec/hutch/error_handlers/honeybadger_spec.rb +36 -0
  44. data/spec/hutch/error_handlers/logger_spec.rb +15 -0
  45. data/spec/hutch/error_handlers/sentry_spec.rb +20 -0
  46. data/spec/hutch/logger_spec.rb +28 -0
  47. data/spec/hutch/message_spec.rb +38 -0
  48. data/spec/hutch/serializers/json_spec.rb +17 -0
  49. data/spec/hutch/worker_spec.rb +99 -0
  50. data/spec/hutch_spec.rb +87 -0
  51. data/spec/spec_helper.rb +40 -0
  52. metadata +194 -0
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hutch::Logging do
4
+ let(:dummy_object) do
5
+ class DummyObject
6
+ include Hutch::Logging
7
+ end
8
+ end
9
+
10
+ describe '#logger' do
11
+ context 'with the default logger' do
12
+ subject { Hutch::Logging.logger }
13
+
14
+ it { is_expected.to be_instance_of(Logger) }
15
+ end
16
+
17
+ context 'with a custom logger' do
18
+ let(:dummy_logger) { double("Dummy logger", warn: true, info: true) }
19
+ after { Hutch::Logging.setup_logger }
20
+
21
+ it "users the custom logger" do
22
+ Hutch::Logging.logger = dummy_logger
23
+ expect(Hutch::Logging.logger).to eq(dummy_logger)
24
+ end
25
+ end
26
+ end
27
+ end
28
+
@@ -0,0 +1,38 @@
1
+ require 'hutch/message'
2
+
3
+ describe Hutch::Message do
4
+ let(:delivery_info) { double('Delivery Info') }
5
+ let(:props) { double('Properties', content_type: "application/json") }
6
+ let(:body) {{ foo: 'bar' }.with_indifferent_access}
7
+ let(:json_body) { MultiJson.dump(body) }
8
+ subject(:message) { Hutch::Message.new(delivery_info, props, json_body, Hutch::Config[:serializer]) }
9
+
10
+ describe '#body' do
11
+ subject { super().body }
12
+ it { is_expected.to eq(body) }
13
+ end
14
+
15
+ describe '[]' do
16
+ subject { message[:foo] }
17
+ it { is_expected.to eq('bar') }
18
+ end
19
+
20
+ [:message_id, :timestamp].each do |method|
21
+ describe method.to_s do
22
+ it 'delegates to @properties' do
23
+ expect(props).to receive(method)
24
+ message.send(method)
25
+ end
26
+ end
27
+ end
28
+
29
+ [:routing_key, :exchange].each do |method|
30
+ describe method.to_s do
31
+ it 'delegates to @delivery_info' do
32
+ expect(delivery_info).to receive(method)
33
+ message.send(method)
34
+ end
35
+ end
36
+ end
37
+ end
38
+
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hutch::Serializers::JSON do
4
+ let(:subject) { described_class }
5
+
6
+ it "encode/decode" do
7
+ payload = { a: 1, b: 2 }
8
+ encoded = subject.encode(payload)
9
+ decoded = subject.decode(encoded)
10
+
11
+ expect(encoded).to eq "{\"a\":1,\"b\":2}"
12
+ expect(decoded).to eq("a" => 1, "b" => 2)
13
+ expect(decoded[:a]).to eq 1
14
+ expect(decoded[:b]).to eq 2
15
+ end
16
+
17
+ end
@@ -0,0 +1,99 @@
1
+ require 'spec_helper'
2
+ require 'hutch/worker'
3
+
4
+ describe Hutch::Worker do
5
+ let(:consumer) { double('Consumer', routing_keys: %w( a b c ),
6
+ get_queue_name: 'consumer', get_arguments: {},
7
+ get_serializer: nil) }
8
+ let(:consumers) { [consumer, double('Consumer')] }
9
+ let(:broker) { Hutch::Broker.new }
10
+ subject(:worker) { Hutch::Worker.new(broker, consumers) }
11
+
12
+ describe '#setup_queues' do
13
+ it 'sets up queues for each of the consumers' do
14
+ consumers.each do |consumer|
15
+ expect(worker).to receive(:setup_queue).with(consumer)
16
+ end
17
+ worker.setup_queues
18
+ end
19
+ end
20
+
21
+ describe '#setup_queue' do
22
+ let(:queue) { double('Queue', bind: nil, subscribe: nil) }
23
+ before { allow(worker).to receive_messages(consumer_queue: queue) }
24
+ before { allow(broker).to receive_messages(queue: queue, bind_queue: nil) }
25
+
26
+ it 'creates a queue' do
27
+ expect(broker).to receive(:queue).with(consumer.get_queue_name, consumer.get_arguments).and_return(queue)
28
+ worker.setup_queue(consumer)
29
+ end
30
+
31
+ it 'binds the queue to each of the routing keys' do
32
+ expect(broker).to receive(:bind_queue).with(queue, %w( a b c ))
33
+ worker.setup_queue(consumer)
34
+ end
35
+
36
+ it 'sets up a subscription' do
37
+ expect(queue).to receive(:subscribe).with(manual_ack: true)
38
+ worker.setup_queue(consumer)
39
+ end
40
+ end
41
+
42
+ describe '#handle_message' do
43
+ let(:payload) { '{}' }
44
+ let(:consumer_instance) { double('Consumer instance') }
45
+ let(:delivery_info) { double('Delivery Info', routing_key: '',
46
+ delivery_tag: 'dt') }
47
+ let(:properties) { double('Properties', message_id: nil, content_type: "application/json") }
48
+ before { allow(consumer).to receive_messages(new: consumer_instance) }
49
+ before { allow(broker).to receive(:ack) }
50
+ before { allow(broker).to receive(:nack) }
51
+ before { allow(consumer_instance).to receive(:broker=) }
52
+ before { allow(consumer_instance).to receive(:delivery_info=) }
53
+
54
+ it 'passes the message to the consumer' do
55
+ expect(consumer_instance).to receive(:process).
56
+ with(an_instance_of(Hutch::Message))
57
+ worker.handle_message(consumer, delivery_info, properties, payload)
58
+ end
59
+
60
+ it 'acknowledges the message' do
61
+ allow(consumer_instance).to receive(:process)
62
+ expect(broker).to receive(:ack).with(delivery_info.delivery_tag)
63
+ worker.handle_message(consumer, delivery_info, properties, payload)
64
+ end
65
+
66
+ context 'when the consumer raises an exception' do
67
+ before { allow(consumer_instance).to receive(:process).and_raise('a consumer error') }
68
+
69
+ it 'logs the error' do
70
+ Hutch::Config[:error_handlers].each do |backend|
71
+ expect(backend).to receive(:handle)
72
+ end
73
+ worker.handle_message(consumer, delivery_info, properties, payload)
74
+ end
75
+
76
+ it 'rejects the message' do
77
+ expect(broker).to receive(:nack).with(delivery_info.delivery_tag)
78
+ worker.handle_message(consumer, delivery_info, properties, payload)
79
+ end
80
+ end
81
+
82
+ context "when the payload is not valid json" do
83
+ let(:payload) { "Not Valid JSON" }
84
+
85
+ it 'logs the error' do
86
+ Hutch::Config[:error_handlers].each do |backend|
87
+ expect(backend).to receive(:handle)
88
+ end
89
+ worker.handle_message(consumer, delivery_info, properties, payload)
90
+ end
91
+
92
+ it 'rejects the message' do
93
+ expect(broker).to receive(:nack).with(delivery_info.delivery_tag)
94
+ worker.handle_message(consumer, delivery_info, properties, payload)
95
+ end
96
+ end
97
+ end
98
+ end
99
+
@@ -0,0 +1,87 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hutch do
4
+ describe '.register_consumer' do
5
+ let(:consumer_a) { double('Consumer') }
6
+ let(:consumer_b) { double('Consumer') }
7
+
8
+ it 'saves the consumers in the global consumer list' do
9
+ Hutch.register_consumer(consumer_a)
10
+ Hutch.register_consumer(consumer_b)
11
+ expect(Hutch.consumers).to include consumer_a
12
+ expect(Hutch.consumers).to include consumer_b
13
+ end
14
+ end
15
+
16
+ describe '.connect' do
17
+ context 'not connected' do
18
+ let(:options) { double 'options' }
19
+ let(:config) { double 'config' }
20
+ let(:broker) { double 'broker' }
21
+ let(:action) { Hutch.connect(options, config) }
22
+
23
+ it 'passes options and config' do
24
+ expect(Hutch::Broker).to receive(:new).with(config).and_return broker
25
+ expect(broker).to receive(:connect).with options
26
+
27
+ action
28
+ end
29
+
30
+ end
31
+
32
+ context 'connected' do
33
+ before { allow(Hutch).to receive(:connected?).and_return true }
34
+
35
+ it 'does not reconnect' do
36
+ expect(Hutch::Broker).not_to receive :new
37
+ Hutch.connect
38
+ end
39
+ end
40
+ end
41
+
42
+ describe '.connected?' do
43
+ subject(:connected?) { Hutch.connected? }
44
+
45
+ before { allow(Hutch).to receive(:broker).and_return(broker) }
46
+
47
+ context 'without a broker' do
48
+ let(:broker) { nil }
49
+
50
+ it { expect(connected?).to be_falsey }
51
+ end
52
+
53
+ context 'without a connection' do
54
+ let(:connection) { nil }
55
+ let(:broker) { double(:broker, connection: connection) }
56
+
57
+ it { expect(connected?).to be_falsey }
58
+ end
59
+
60
+ context 'with a closed connection' do
61
+ let(:connection) { double(:connection, open?: false) }
62
+ let(:broker) { double(:broker, connection: connection) }
63
+
64
+ it { expect(connected?).to be_falsey }
65
+ end
66
+
67
+ context 'with an opened connection' do
68
+ let(:connection) { double(:connection, open?: true) }
69
+ let(:broker) { double(:broker, connection: connection) }
70
+
71
+ it { expect(connected?).to be_truthy }
72
+ end
73
+ end
74
+
75
+ describe '#publish' do
76
+ let(:broker) { double(Hutch::Broker) }
77
+ let(:args) { ['test.key', 'message', { headers: { foo: 'bar' } }] }
78
+
79
+ before { allow(Hutch).to receive(:broker).and_return(broker) }
80
+
81
+ it 'delegates to Hutch::Broker#publish' do
82
+ expect(broker).to receive(:publish).with(*args)
83
+ Hutch.publish(*args)
84
+ end
85
+ end
86
+ end
87
+
@@ -0,0 +1,40 @@
1
+ require 'simplecov'
2
+ if ENV['TRAVIS']
3
+ require 'coveralls'
4
+ SimpleCov.formatter = Coveralls::SimpleCov::Formatter
5
+ end
6
+
7
+ SimpleCov.start do
8
+ add_filter '/spec/'
9
+ add_filter '/.bundle/'
10
+ end
11
+
12
+ require 'raven'
13
+ require 'hutch'
14
+ require 'logger'
15
+
16
+ RSpec.configure do |config|
17
+ config.before(:all) { Hutch::Config.log_level = Logger::FATAL }
18
+ config.raise_errors_for_deprecations!
19
+
20
+ if defined?(JRUBY_VERSION)
21
+ config.filter_run_excluding adapter: :bunny
22
+ else
23
+ config.filter_run_excluding adapter: :march_hare
24
+ end
25
+ end
26
+
27
+ # Constants (classes, etc) defined within a block passed to this method
28
+ # will be removed from the global namespace after the block as run.
29
+ def isolate_constants
30
+ existing_constants = Object.constants
31
+ yield
32
+ ensure
33
+ (Object.constants - existing_constants).each do |constant|
34
+ Object.send(:remove_const, constant)
35
+ end
36
+ end
37
+
38
+ def deep_copy(obj)
39
+ Marshal.load(Marshal.dump(obj))
40
+ end
metadata ADDED
@@ -0,0 +1,194 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hutch
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.19.0
5
+ platform: java
6
+ authors:
7
+ - Harry Marr
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-10-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: 2.11.0
19
+ name: march_hare
20
+ prerelease: false
21
+ type: :runtime
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 2.11.0
27
+ - !ruby/object:Gem::Dependency
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: 0.0.7
33
+ name: carrot-top
34
+ prerelease: false
35
+ type: :runtime
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.0.7
41
+ - !ruby/object:Gem::Dependency
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: 1.11.2
47
+ name: multi_json
48
+ prerelease: false
49
+ type: :runtime
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 1.11.2
55
+ - !ruby/object:Gem::Dependency
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '3.0'
61
+ name: activesupport
62
+ prerelease: false
63
+ type: :runtime
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '3.0'
75
+ name: rspec
76
+ prerelease: false
77
+ type: :development
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.0'
83
+ - !ruby/object:Gem::Dependency
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: 0.7.1
89
+ name: simplecov
90
+ prerelease: false
91
+ type: :development
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.7.1
97
+ description: Hutch is a Ruby library for enabling asynchronous inter-service communication using RabbitMQ.
98
+ email:
99
+ - developers@gocardless.com
100
+ executables:
101
+ - hutch
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".gitignore"
106
+ - ".travis.yml"
107
+ - CHANGELOG.md
108
+ - Gemfile
109
+ - Guardfile
110
+ - LICENSE
111
+ - README.md
112
+ - Rakefile
113
+ - bin/hutch
114
+ - circle.yml
115
+ - examples/consumer.rb
116
+ - examples/producer.rb
117
+ - hutch.gemspec
118
+ - lib/hutch.rb
119
+ - lib/hutch/adapter.rb
120
+ - lib/hutch/adapters/bunny.rb
121
+ - lib/hutch/adapters/march_hare.rb
122
+ - lib/hutch/broker.rb
123
+ - lib/hutch/cli.rb
124
+ - lib/hutch/config.rb
125
+ - lib/hutch/consumer.rb
126
+ - lib/hutch/error_handlers.rb
127
+ - lib/hutch/error_handlers/airbrake.rb
128
+ - lib/hutch/error_handlers/honeybadger.rb
129
+ - lib/hutch/error_handlers/logger.rb
130
+ - lib/hutch/error_handlers/sentry.rb
131
+ - lib/hutch/exceptions.rb
132
+ - lib/hutch/logging.rb
133
+ - lib/hutch/message.rb
134
+ - lib/hutch/serializers/identity.rb
135
+ - lib/hutch/serializers/json.rb
136
+ - lib/hutch/tracers.rb
137
+ - lib/hutch/tracers/newrelic.rb
138
+ - lib/hutch/tracers/null_tracer.rb
139
+ - lib/hutch/version.rb
140
+ - lib/hutch/worker.rb
141
+ - spec/hutch/broker_spec.rb
142
+ - spec/hutch/cli_spec.rb
143
+ - spec/hutch/config_spec.rb
144
+ - spec/hutch/consumer_spec.rb
145
+ - spec/hutch/error_handlers/airbrake_spec.rb
146
+ - spec/hutch/error_handlers/honeybadger_spec.rb
147
+ - spec/hutch/error_handlers/logger_spec.rb
148
+ - spec/hutch/error_handlers/sentry_spec.rb
149
+ - spec/hutch/logger_spec.rb
150
+ - spec/hutch/message_spec.rb
151
+ - spec/hutch/serializers/json_spec.rb
152
+ - spec/hutch/worker_spec.rb
153
+ - spec/hutch_spec.rb
154
+ - spec/spec_helper.rb
155
+ homepage: https://github.com/gocardless/hutch
156
+ licenses:
157
+ - MIT
158
+ metadata: {}
159
+ post_install_message:
160
+ rdoc_options: []
161
+ require_paths:
162
+ - lib
163
+ required_ruby_version: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
168
+ required_rubygems_version: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - ">="
171
+ - !ruby/object:Gem::Version
172
+ version: '0'
173
+ requirements: []
174
+ rubyforge_project:
175
+ rubygems_version: 2.4.8
176
+ signing_key:
177
+ specification_version: 4
178
+ summary: Easy inter-service communication using RabbitMQ.
179
+ test_files:
180
+ - spec/hutch/broker_spec.rb
181
+ - spec/hutch/cli_spec.rb
182
+ - spec/hutch/config_spec.rb
183
+ - spec/hutch/consumer_spec.rb
184
+ - spec/hutch/error_handlers/airbrake_spec.rb
185
+ - spec/hutch/error_handlers/honeybadger_spec.rb
186
+ - spec/hutch/error_handlers/logger_spec.rb
187
+ - spec/hutch/error_handlers/sentry_spec.rb
188
+ - spec/hutch/logger_spec.rb
189
+ - spec/hutch/message_spec.rb
190
+ - spec/hutch/serializers/json_spec.rb
191
+ - spec/hutch/worker_spec.rb
192
+ - spec/hutch_spec.rb
193
+ - spec/spec_helper.rb
194
+ has_rdoc: