hutch 1.2.0 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9c376d628987a9352a8ff9e49cd48ae0c12364cc3f9393185e8c811ff3052213
4
- data.tar.gz: 3aa07c8285817c1fefa10b7dc2b65e3fccf0b62ffbaf7a89e4b09f9a6db67035
3
+ metadata.gz: 02b687d56ec0d56dc49c07722e3e55c3b86ca274008394209b3fe60d6ecb8bf4
4
+ data.tar.gz: a6c38c9b5f26944f7abb3b078d4cf693bb29ed2fb08987b7f4bc5e4fe2a70f78
5
5
  SHA512:
6
- metadata.gz: 0c0ba8155050290ebe63628ce10f9fdbd93e4ec483ce8e465564f9635913082d662f2b9f05ca3227f5ad6f5d9c773e9e9653abfbc867f816db0ddf589093d388
7
- data.tar.gz: 2ef54abbde9959378b15d1e60062b62ae0b55e8299029fa4fade407f6f9006b6df327f547dc2ba771638fa8d1e512860f0a78f4dc1fe145b337afb4d4000ea64
6
+ metadata.gz: 85513bc753214f4a077c4a50510519082e3f5bc8aee75cba1df09461be9723e4a8d438a97f3c6bd3025fb59a0d7008adb5577c7faee082367ddd85f7239f748a
7
+ data.tar.gz: f0d6fcc77c94a0349104243c3daac3e2f4fe057ce96a4b251c0577969fcaf1b69860ca3eadd163aac353275bbe517847573f6064ea46cad70aa8979004c6e9f7
@@ -1,13 +1,10 @@
1
1
  name: Test
2
2
 
3
- concurrency:
3
+ concurrency:
4
4
  group: ${{ github.ref }}
5
5
  cancel-in-progress: true
6
6
 
7
- on:
8
- push:
9
- branches: [ master ]
10
- pull_request:
7
+ on: [push,pull_request,workflow_dispatch]
11
8
 
12
9
  jobs:
13
10
  test:
@@ -25,13 +22,15 @@ jobs:
25
22
  strategy:
26
23
  fail-fast: false
27
24
  matrix:
28
- ruby-version:
29
- - 2.7
30
- - 3.0
31
- - 3.1
25
+ ruby-version:
26
+ - '2.7'
27
+ - '3.0'
28
+ - '3.1'
29
+ - '3.2'
30
+ - '3.3'
32
31
 
33
32
  steps:
34
- - uses: actions/checkout@v3
33
+ - uses: actions/checkout@v4
35
34
  - name: Set up Ruby
36
35
  # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
37
36
  # change this to (see https://github.com/ruby/setup-ruby#versioning):
data/CHANGELOG.md CHANGED
@@ -1,4 +1,37 @@
1
+ ## 1.3.2 (in development)
2
+
3
+ No changes yet.
4
+
5
+ ## 1.3.1 (Dec 11, 2024)
6
+
7
+ ### Rails 8.x Compatibility
8
+
9
+ Contributed by @drobny.
10
+
11
+ GitHub issue: [#404](https://github.com/ruby-amqp/hutch/pull/404)
12
+
13
+
14
+ ## 1.3.0 (Nov 11, 2024)
15
+
16
+ ### Ruby 3.2 Compatibility
17
+
18
+ GitHub issue: [#392](https://github.com/ruby-amqp/hutch/pull/392)
19
+
20
+ ### Relaxed ActiveSupport Dependency Constraints
21
+
22
+ Contributed by @drobny.
23
+
24
+ GitHub issue: [#402](https://github.com/ruby-amqp/hutch/pull/402)
25
+
26
+ ### Client-Provided Connection Name
27
+
28
+ Contributed by @sharshenov.
29
+
30
+ GitHub issue: [#399](https://github.com/ruby-amqp/hutch/pull/399)
31
+
32
+
1
33
  ## 1.1.1 (March 18th, 2022)
34
+
2
35
  ### Dependency Bump
3
36
 
4
37
  Hutch now allows ActiveSupport 7.x.
data/Gemfile CHANGED
@@ -1,13 +1,13 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- ruby '>= 2.3.0'
3
+ ruby '>= 2.7.0'
4
4
 
5
5
  gemspec
6
6
 
7
7
  group :development do
8
8
  gem "rake"
9
- gem "guard", "~> 2.14", platform: :mri_23
10
- gem "guard-rspec", "~> 4.7", platform: :mri_23
9
+ gem "guard", "~> 2.14", platform: :mri
10
+ gem "guard-rspec", "~> 4.7", platform: :mri
11
11
 
12
12
  gem "yard", "~> 0.9"
13
13
  gem 'kramdown', "> 0", platform: :jruby
@@ -16,21 +16,20 @@ group :development do
16
16
  end
17
17
 
18
18
  group :development, :test do
19
- gem "rspec", "~> 3.5"
20
- gem "simplecov", "~> 0.12"
19
+ gem "rspec", "~> 3.12"
20
+ gem "simplecov", "~> 0.21"
21
21
 
22
22
  gem "sentry-raven"
23
23
  gem "sentry-ruby"
24
24
  gem "honeybadger"
25
- gem "coveralls", "~> 0.8.15", require: false
26
25
  gem "newrelic_rpm"
27
- gem "ddtrace", "~> 0.54.2"
28
- gem "airbrake", "~> 10.0"
26
+ gem "ddtrace", "~> 1.8"
27
+ gem "airbrake", "~> 13.0"
29
28
  gem "rollbar"
30
29
  gem "bugsnag"
31
30
  end
32
31
 
33
32
  group :development, :darwin do
34
- gem "rb-fsevent", "~> 0.9"
33
+ gem "rb-fsevent", "~> 0.11.2"
35
34
  gem "growl", "~> 1.0.3"
36
35
  end
data/README.md CHANGED
@@ -406,6 +406,7 @@ Known configuration parameters are:
406
406
  * `error_acknowledgements`: a chain of responsibility of objects that acknowledge/reject/requeue messages when an
407
407
  exception happens, see classes in `Hutch::Acknowledgements`.
408
408
  * `mq_exchange`: exchange to use for publishing (default: `hutch`)
409
+ * `mq_client_properties`: Bunny's [client properties](https://www.rabbitmq.com/docs/connections#capabilities) (default: `{}`)
409
410
  * `heartbeat`: [RabbitMQ heartbeat timeout](http://rabbitmq.com/heartbeats.html) (default: `30`)
410
411
  * `connection_timeout`: Bunny's socket open timeout (default: `11`)
411
412
  * `read_timeout`: Bunny's socket read timeout (default: `11`)
@@ -542,6 +543,13 @@ Generate with
542
543
  <td><tt>HUTCH_CHANNEL_PREFETCH</tt></td>
543
544
  <td><p>The <tt>basic.qos</tt> prefetch value to use.</p></td>
544
545
  </tr>
546
+ <tr>
547
+ <td><tt>connection_name</tt></td>
548
+ <td>nil</td>
549
+ <td>String</td>
550
+ <td><tt>HUTCH_CONNECTION_NAME</tt></td>
551
+ <td><p><a href="https://www.rabbitmq.com/docs/connections#client-provided-names">Client-Provided Connection Name</a></p></td>
552
+ </tr>
545
553
  <tr>
546
554
  <td><tt>connection_timeout</tt></td>
547
555
  <td>11</td>
data/hutch.gemspec CHANGED
@@ -3,20 +3,20 @@ require File.expand_path('../lib/hutch/version', __FILE__)
3
3
  Gem::Specification.new do |gem|
4
4
  if defined?(JRUBY_VERSION)
5
5
  gem.platform = 'java'
6
- gem.add_runtime_dependency 'march_hare', '>= 3.0.0'
6
+ gem.add_runtime_dependency 'march_hare', '>= 4.5.0'
7
7
  else
8
8
  gem.platform = Gem::Platform::RUBY
9
- gem.add_runtime_dependency 'bunny', '>= 2.19', '< 3.0'
9
+ gem.add_runtime_dependency 'bunny', '>= 2.23', '< 3.0'
10
10
  end
11
11
  gem.add_runtime_dependency 'carrot-top', '~> 0.0.7'
12
12
  gem.add_runtime_dependency 'multi_json', '~> 1.15'
13
- gem.add_runtime_dependency 'activesupport', '>= 4.2', '< 8'
13
+ gem.add_runtime_dependency 'activesupport', '>= 4.2'
14
14
 
15
15
  gem.name = 'hutch'
16
16
  gem.summary = 'Opinionated asynchronous inter-service communication using RabbitMQ'
17
17
  gem.description = 'Hutch is a Ruby library for enabling asynchronous inter-service communication using RabbitMQ'
18
18
  gem.version = Hutch::VERSION.dup
19
- gem.required_ruby_version = '>= 2.2'
19
+ gem.required_ruby_version = '>= 2.6'
20
20
  gem.authors = ['Harry Marr', 'Michael Klishin']
21
21
  gem.homepage = 'https://github.com/ruby-amqp/hutch'
22
22
  gem.require_paths = ['lib']
data/lib/hutch/broker.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'active_support/core_ext/object/blank'
2
2
 
3
3
  require 'carrot-top'
4
+ require 'ostruct'
4
5
  require 'hutch/logging'
5
6
  require 'hutch/exceptions'
6
7
  require 'hutch/publisher'
@@ -298,6 +299,8 @@ module Hutch
298
299
  params[:tls_ca_certificates] = @config[:mq_tls_ca_certificates]
299
300
  end
300
301
  params[:heartbeat] = @config[:heartbeat]
302
+ params[:client_properties] = @config[:mq_client_properties]
303
+ params[:connection_name] = @config[:connection_name]
301
304
  params[:connection_timeout] = @config[:connection_timeout]
302
305
  params[:read_timeout] = @config[:read_timeout]
303
306
  params[:write_timeout] = @config[:write_timeout]
data/lib/hutch/cli.rb CHANGED
@@ -234,7 +234,7 @@ module Hutch
234
234
  end
235
235
 
236
236
  def abort_without_file(file, file_description, &block)
237
- abort_with_message("#{file_description} '#{file}' not found") unless File.exists?(file)
237
+ abort_with_message("#{file_description} '#{file}' not found") unless File.exist?(file)
238
238
 
239
239
  yield
240
240
  end
data/lib/hutch/config.rb CHANGED
@@ -86,6 +86,9 @@ module Hutch
86
86
  # Default: `0`, no limit. See Bunny and RabbitMQ documentation.
87
87
  number_setting :channel_prefetch, 0
88
88
 
89
+ # [Client-Provided Connection Name](https://www.rabbitmq.com/docs/connections#client-provided-names)
90
+ string_setting :connection_name, nil
91
+
89
92
  # Bunny's socket open timeout
90
93
  number_setting :connection_timeout, 11
91
94
 
@@ -171,6 +174,7 @@ module Hutch
171
174
  # @return [Hash]
172
175
  def self.default_config
173
176
  @settings_defaults.merge({
177
+ mq_client_properties: {},
174
178
  mq_exchange_options: {},
175
179
  mq_tls_cert: nil,
176
180
  mq_tls_key: nil,
@@ -1,4 +1,5 @@
1
1
  require 'ddtrace'
2
+ require 'ddtrace/auto_instrument'
2
3
 
3
4
  module Hutch
4
5
  module Tracers
@@ -8,7 +9,7 @@ module Hutch
8
9
  end
9
10
 
10
11
  def handle(message)
11
- ::Datadog.tracer.trace(@klass.class.name, service: 'hutch', span_type: 'rabbitmq') do
12
+ ::Datadog::Tracing.trace(@klass.class.name, continue_from: nil, service: 'hutch', type: 'rabbitmq') do
12
13
  @klass.process(message)
13
14
  end
14
15
  end
data/lib/hutch/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Hutch
2
- VERSION = '1.2.0'.freeze
2
+ VERSION = '1.3.1'.freeze
3
3
  end
data/lib/hutch/worker.rb CHANGED
@@ -74,7 +74,7 @@ module Hutch
74
74
  @broker.ack(delivery_info.delivery_tag) unless consumer_instance.message_rejected?
75
75
  rescue => ex
76
76
  acknowledge_error(delivery_info, properties, @broker, ex)
77
- handle_error(properties, payload, consumer, ex)
77
+ handle_error(properties, payload, consumer, ex, delivery_info)
78
78
  end
79
79
 
80
80
  def with_tracing(klass)
@@ -83,7 +83,7 @@ module Hutch
83
83
 
84
84
  def handle_error(*args)
85
85
  Hutch::Config[:error_handlers].each do |backend|
86
- backend.handle(*args)
86
+ backend.handle *args.first(backend.method(:handle).arity)
87
87
  end
88
88
  end
89
89
 
@@ -8,6 +8,7 @@ describe Hutch::ErrorHandlers::Bugsnag do
8
8
  before do
9
9
  Bugsnag.configure do |bugsnag|
10
10
  bugsnag.api_key = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
11
+ bugsnag.logger = Logger.new(File::NULL) # suppress logging
11
12
  end
12
13
  end
13
14
 
@@ -15,7 +15,7 @@ describe Hutch::ErrorHandlers::SentryRaven do
15
15
  end
16
16
 
17
17
  it "logs the error to Sentry" do
18
- expect(Raven).to receive(:capture_exception).with(error, extra: { payload: payload })
18
+ expect(Raven).to receive(:capture_exception).with(error, {extra: { payload: payload }})
19
19
  error_handler.handle(properties, payload, double, error)
20
20
  end
21
21
  end
@@ -1,6 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe Hutch::Tracers::Datadog do
4
+ ::Datadog.logger.level = Logger::FATAL # suppress logging
5
+
4
6
  describe "#handle" do
5
7
  subject(:handle) { tracer.handle(message) }
6
8
 
@@ -25,14 +27,14 @@ RSpec.describe Hutch::Tracers::Datadog do
25
27
  let(:message) { double(:message) }
26
28
 
27
29
  before do
28
- allow(Datadog.tracer).to receive(:trace).and_call_original
30
+ allow(::Datadog::Tracing).to receive(:trace).and_call_original
29
31
  end
30
32
 
31
33
  it 'uses Datadog tracer' do
32
34
  handle
33
35
 
34
- expect(Datadog.tracer).to have_received(:trace).with('ClassName',
35
- hash_including(service: 'hutch', span_type: 'rabbitmq'))
36
+ expect(::Datadog::Tracing).to have_received(:trace).with('ClassName',
37
+ hash_including(service: 'hutch', type: 'rabbitmq'))
36
38
  end
37
39
 
38
40
  it 'processes the message' do
@@ -69,29 +69,32 @@ describe Hutch::Worker do
69
69
  end
70
70
 
71
71
  describe '#handle_message' do
72
+ subject { worker.handle_message(consumer, delivery_info, properties, payload) }
72
73
  let(:payload) { '{}' }
73
74
  let(:consumer_instance) { double('Consumer instance') }
74
75
  let(:delivery_info) { double('Delivery Info', routing_key: '',
75
76
  delivery_tag: 'dt') }
76
77
  let(:properties) { double('Properties', message_id: nil, content_type: "application/json") }
78
+ let(:log) { StringIO.new }
77
79
  before { allow(consumer).to receive_messages(new: consumer_instance) }
78
80
  before { allow(broker).to receive(:ack) }
79
81
  before { allow(broker).to receive(:nack) }
80
82
  before { allow(consumer_instance).to receive(:broker=) }
81
83
  before { allow(consumer_instance).to receive(:delivery_info=) }
84
+ before { allow(Hutch::Logging).to receive(:logger).and_return(Logger.new(log)) }
82
85
 
83
86
  it 'passes the message to the consumer' do
84
87
  expect(consumer_instance).to receive(:process).
85
88
  with(an_instance_of(Hutch::Message))
86
89
  expect(consumer_instance).to receive(:message_rejected?).and_return(false)
87
- worker.handle_message(consumer, delivery_info, properties, payload)
90
+ subject
88
91
  end
89
92
 
90
93
  it 'acknowledges the message' do
91
94
  allow(consumer_instance).to receive(:process)
92
95
  expect(broker).to receive(:ack).with(delivery_info.delivery_tag)
93
96
  expect(consumer_instance).to receive(:message_rejected?).and_return(false)
94
- worker.handle_message(consumer, delivery_info, properties, payload)
97
+ subject
95
98
  end
96
99
 
97
100
  context 'when the consumer fails and a requeue is configured' do
@@ -108,40 +111,79 @@ describe Hutch::Worker do
108
111
  expect(broker).to_not receive(:nack)
109
112
  expect(broker).to receive(:requeue)
110
113
 
111
- worker.handle_message(consumer, delivery_info, properties, payload)
114
+ subject
112
115
  end
113
116
  end
114
117
 
115
118
 
116
119
  context 'when the consumer raises an exception' do
120
+ let(:expected_log) { /ERROR .+ error in consumer .+ RuntimeError .+ backtrace:/m }
117
121
  before { allow(consumer_instance).to receive(:process).and_raise('a consumer error') }
118
122
 
119
123
  it 'logs the error' do
120
- Hutch::Config[:error_handlers].each do |backend|
121
- expect(backend).to receive(:handle)
122
- end
123
- worker.handle_message(consumer, delivery_info, properties, payload)
124
+ expect { subject }.to change { log.tap(&:rewind).read }.from("").to(expected_log)
124
125
  end
125
126
 
126
127
  it 'rejects the message' do
127
128
  expect(broker).to receive(:nack).with(delivery_info.delivery_tag)
128
- worker.handle_message(consumer, delivery_info, properties, payload)
129
+ subject
130
+ end
131
+
132
+ context 'when a custom error handler supports delivery info' do
133
+ let(:error_handler) do
134
+ Class.new(Hutch::ErrorHandlers::Base) do
135
+ def handle(_properties, _payload, _consumer, _ex, delivery_info)
136
+ raise unless delivery_info.delivery_tag == 'dt'
137
+ puts 'handled!'
138
+ end
139
+ end
140
+ end
141
+
142
+ around do |example|
143
+ original = Hutch::Config[:error_handlers]
144
+ Hutch::Config[:error_handlers] = [error_handler.new]
145
+ example.run
146
+ Hutch::Config[:error_handlers] = original
147
+ end
148
+
149
+ it 'calls the custom handler with delivery info' do
150
+ expect { subject }.to output("handled!\n").to_stdout
151
+ end
152
+ end
153
+
154
+ context 'when a custom error handler does not support delivery info' do
155
+ let(:error_handler) do
156
+ Class.new(Hutch::ErrorHandlers::Base) do
157
+ def handle(_properties, _payload, _consumer, _ex)
158
+ puts 'handled!'
159
+ end
160
+ end
161
+ end
162
+
163
+ around do |example|
164
+ original = Hutch::Config[:error_handlers]
165
+ Hutch::Config[:error_handlers] = [error_handler.new]
166
+ example.run
167
+ Hutch::Config[:error_handlers] = original
168
+ end
169
+
170
+ it 'calls the custom handler with delivery info' do
171
+ expect { subject }.to output("handled!\n").to_stdout
172
+ end
129
173
  end
130
174
  end
131
175
 
132
176
  context "when the payload is not valid json" do
133
177
  let(:payload) { "Not Valid JSON" }
178
+ let(:expected_log) { /ERROR .+ error in consumer .+ MultiJson::ParseError .+ backtrace:/m }
134
179
 
135
180
  it 'logs the error' do
136
- Hutch::Config[:error_handlers].each do |backend|
137
- expect(backend).to receive(:handle)
138
- end
139
- worker.handle_message(consumer, delivery_info, properties, payload)
181
+ expect { subject }.to change { log.tap(&:rewind).read }.from("").to(expected_log)
140
182
  end
141
183
 
142
184
  it 'rejects the message' do
143
185
  expect(broker).to receive(:nack).with(delivery_info.delivery_tag)
144
- worker.handle_message(consumer, delivery_info, properties, payload)
186
+ subject
145
187
  end
146
188
  end
147
189
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hutch
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Harry Marr
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-12-20 00:00:00.000000000 Z
12
+ date: 2024-12-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bunny
@@ -17,7 +17,7 @@ dependencies:
17
17
  requirements:
18
18
  - - ">="
19
19
  - !ruby/object:Gem::Version
20
- version: '2.19'
20
+ version: '2.23'
21
21
  - - "<"
22
22
  - !ruby/object:Gem::Version
23
23
  version: '3.0'
@@ -27,7 +27,7 @@ dependencies:
27
27
  requirements:
28
28
  - - ">="
29
29
  - !ruby/object:Gem::Version
30
- version: '2.19'
30
+ version: '2.23'
31
31
  - - "<"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '3.0'
@@ -66,9 +66,6 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '4.2'
69
- - - "<"
70
- - !ruby/object:Gem::Version
71
- version: '8'
72
69
  type: :runtime
73
70
  prerelease: false
74
71
  version_requirements: !ruby/object:Gem::Requirement
@@ -76,9 +73,6 @@ dependencies:
76
73
  - - ">="
77
74
  - !ruby/object:Gem::Version
78
75
  version: '4.2'
79
- - - "<"
80
- - !ruby/object:Gem::Version
81
- version: '8'
82
76
  description: Hutch is a Ruby library for enabling asynchronous inter-service communication
83
77
  using RabbitMQ
84
78
  email:
@@ -178,14 +172,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
178
172
  requirements:
179
173
  - - ">="
180
174
  - !ruby/object:Gem::Version
181
- version: '2.2'
175
+ version: '2.6'
182
176
  required_rubygems_version: !ruby/object:Gem::Requirement
183
177
  requirements:
184
178
  - - ">="
185
179
  - !ruby/object:Gem::Version
186
180
  version: '0'
187
181
  requirements: []
188
- rubygems_version: 3.3.7
182
+ rubygems_version: 3.5.22
189
183
  signing_key:
190
184
  specification_version: 4
191
185
  summary: Opinionated asynchronous inter-service communication using RabbitMQ