hutch 0.19.0-java

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.
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: