hutch 0.15.0 → 0.16.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4edfb298acf9e73fb226a3708e76d7e99ad345e3
4
- data.tar.gz: d17eb84b63b21b42501570196abe6ef57ca94cde
3
+ metadata.gz: 0a8fca35975c1fa959a90ec608e978fe3f6c523b
4
+ data.tar.gz: b8b8df85e625956eb974403d37180dfecfff03b4
5
5
  SHA512:
6
- metadata.gz: 99ba07374f0f8bcf407ef537ea0a8342cb4368cf323c0f41deee27a37e1b6cf156dc6a72645bf2ecc6181219a0723c9c6795035d7ac3cc46ad4783f936edd516
7
- data.tar.gz: 8a6abf7f30f6dcb3c88d968deba3115389b6a043293a75609ff5e441c94da55ac3c31d81dad4049f52710ac12bff59d4643f878ee40bac143d35b3070edf8c84
6
+ metadata.gz: f0043f3e29a151a24b38cd18f3f4d8737c37ce77b99001d4fcac6f533904a7eeabdc478bf9b3cd7ac51385ba1da4d97327c71434bbf8ea6fdc026bd4b0431a52
7
+ data.tar.gz: cde750774fa801338a7e54103566eeaff7cd91c6e930c3251fa4f5521ee3599ac19599ab066ca9581f6ee7919d0e769b70818c6337029644ae97d3f3e0cc3672
@@ -3,6 +3,5 @@ rvm:
3
3
  - "2.2"
4
4
  - "2.1"
5
5
  - "2.0"
6
- - "1.9.3"
7
6
  services:
8
7
  - rabbitmq
@@ -1,4 +1,33 @@
1
- ## 0.15.0 — (unreleased)
1
+ ## 0.16.0 — July 19th, 2015
2
+
3
+ ### Support amqps URIs
4
+
5
+ Hutch now automatically enables TLS and changes default port
6
+ when URI scheme is `amqps`.
7
+
8
+ Contributed by Carl Hörberg.
9
+
10
+ ### Hash With Indifferent Access
11
+
12
+ Hutch now uses `HashWithIndifferentAccess` internally
13
+ to reduce use of symbols (which are not garbage collected
14
+ by widely used Ruby versions).
15
+
16
+ Contributed by Teodor Pripoae.
17
+
18
+
19
+ ## 0.15.0 — May 5th, 2015
20
+
21
+ ### Airbrake Error Handler
22
+
23
+ Contributed by Nate Salisbury.
24
+
25
+ ### Ruby 1.9 Support Dropped
26
+
27
+ Ruby 1.9 is no longer supported by Hutch (and soon Bunny 2.0).
28
+ 1.9 is also no longer maintained by the Ruby core team.
29
+
30
+ ### Custom Arguments per Consumers
2
31
 
3
32
  Allow to set custom arguments per consumers by using the `arguments` setter.
4
33
  Arguments are usually used by rabbitmq plugins or to set queue policies. You can
@@ -6,6 +35,23 @@ find a list of supported arguments [here](https://www.rabbitmq.com/extensions.ht
6
35
 
7
36
  Contributed by Pierre-Louis Gottfrois.
8
37
 
38
+ ### Message Processing Tracers
39
+
40
+ Allow to track message processing by using the `:tracer` config option,
41
+ the value should be a class (or fully-qualified string name of a class) that
42
+ implements the tracing interface.
43
+
44
+ A tracer that performs NewRelic instrumentation ships with Hutch
45
+ and requires New Relic gem to be loaded.
46
+
47
+ Contributed by Mirosław Nagaś.
48
+
49
+ ### Added Logger Method to Consumer Module
50
+
51
+ Consumers can now call a logger method to write to Hutch's log.
52
+
53
+ Contributed by Matty Courtney
54
+
9
55
  ## 0.14.0 — Feb 23rd, 2015
10
56
 
11
57
  ### Configurable Socket Timeouts
data/Gemfile CHANGED
@@ -12,6 +12,8 @@ group :development, :test do
12
12
  gem "sentry-raven"
13
13
  gem "honeybadger"
14
14
  gem "coveralls", require: false
15
+ gem "newrelic_rpm"
16
+ gem "airbrake"
15
17
  end
16
18
 
17
19
  group :development, :darwin do
data/README.md CHANGED
@@ -93,6 +93,21 @@ end
93
93
 
94
94
  Custom queue arguments can be found on [this page](https://www.rabbitmq.com/extensions.html).
95
95
 
96
+ Consumers can write to Hutch's log by calling the logger method. The logger method returns
97
+ a [Logger object](http://ruby-doc.org/stdlib-2.1.2/libdoc/logger/rdoc/Logger.html).
98
+
99
+ ```ruby
100
+ class FailedPaymentConsumer
101
+ include Hutch::Consumer
102
+ consume 'gc.ps.payment.failed'
103
+
104
+ def process(message)
105
+ logger.info "Marking payment #{message[:id]} as failed"
106
+ mark_payment_as_failed(message[:id])
107
+ end
108
+ end
109
+ ```
110
+
96
111
  If you are using Hutch with Rails and want to make Hutch log to the Rails
97
112
  logger rather than `stdout`, add this to `config/initializers/hutch.rb`
98
113
 
@@ -103,6 +118,15 @@ Hutch::Logging.logger = Rails.logger
103
118
  See this [RabbitMQ tutorial on topic exchanges](http://www.rabbitmq.com/tutorials/tutorial-five-ruby.html)
104
119
  to learn more.
105
120
 
121
+ ### Message Processing Tracers
122
+
123
+ Tracers allow you to track message processing.
124
+
125
+ #### NewRelic
126
+ ```ruby
127
+ Hutch::Config.set(:tracer, Hutch::Tracers::NewRelic)
128
+ ```
129
+ This will enable NewRelic custom instrumentation. Batteries included! Screenshoots available [here](https://monosnap.com/list/557020a000779174f23467e3).
106
130
 
107
131
  ## Running Hutch
108
132
 
@@ -271,6 +295,7 @@ Known configuration parameters are:
271
295
  * `connection_timeout`: Bunny's socket open timeout (default: `11`)
272
296
  * `read_timeout`: Bunny's socket read timeout (default: `11`)
273
297
  * `write_timemout`: Bunny's socket write timeout (default: `11`)
298
+ * `tracer`: tracer to use to track message processing
274
299
 
275
300
 
276
301
  ## Supported RabbitMQ Versions
@@ -4,6 +4,7 @@ Gem::Specification.new do |gem|
4
4
  gem.add_runtime_dependency 'bunny', '>= 1.7.0'
5
5
  gem.add_runtime_dependency 'carrot-top', '~> 0.0.7'
6
6
  gem.add_runtime_dependency 'multi_json', '~> 1.5'
7
+ gem.add_runtime_dependency 'activesupport', '>= 3.0'
7
8
  gem.add_development_dependency 'rspec', '~> 3.0'
8
9
  gem.add_development_dependency 'simplecov', '~> 0.7.1'
9
10
 
@@ -8,6 +8,7 @@ require 'hutch/cli'
8
8
  require 'hutch/version'
9
9
  require 'hutch/error_handlers'
10
10
  require 'hutch/exceptions'
11
+ require 'hutch/tracers'
11
12
 
12
13
  module Hutch
13
14
 
@@ -24,6 +24,12 @@ module Hutch
24
24
  logger.info "HTTP API use is disabled"
25
25
  end
26
26
 
27
+ if tracing_enabled?
28
+ logger.info "tracing is enabled using #{@config[:tracer]}"
29
+ else
30
+ logger.info "tracing is disabled"
31
+ end
32
+
27
33
  if block_given?
28
34
  begin
29
35
  yield
@@ -63,10 +69,12 @@ module Hutch
63
69
  @config[:mq_vhost] = u.path.sub(/^\//, "")
64
70
  @config[:mq_username] = u.user
65
71
  @config[:mq_password] = u.password
72
+ @config[:mq_tls] = u.scheme == "amqps"
66
73
  end
67
74
 
75
+ tls = @config[:mq_tls]
68
76
  host = @config[:mq_host]
69
- port = @config[:mq_port]
77
+ port = @config.fetch(:mq_port, (tls ? 5671 : 5672))
70
78
  vhost = if @config[:mq_vhost] && "" != @config[:mq_vhost]
71
79
  @config[:mq_vhost]
72
80
  else
@@ -74,7 +82,6 @@ module Hutch
74
82
  end
75
83
  username = @config[:mq_username]
76
84
  password = @config[:mq_password]
77
- tls = @config[:mq_tls]
78
85
  tls_key = @config[:mq_tls_key]
79
86
  tls_cert = @config[:mq_tls_cert]
80
87
  heartbeat = @config[:heartbeat]
@@ -82,8 +89,8 @@ module Hutch
82
89
  read_timeout = @config[:read_timeout]
83
90
  write_timeout = @config[:write_timeout]
84
91
 
85
- protocol = tls ? "amqps://" : "amqp://"
86
- sanitized_uri = "#{protocol}#{username}@#{host}:#{port}/#{vhost.sub(/^\//, '')}"
92
+ scheme = tls ? "amqps" : "amqp"
93
+ sanitized_uri = "#{scheme}://#{username}@#{host}:#{port}/#{vhost.sub(/^\//, '')}"
87
94
  logger.info "connecting to rabbitmq (#{sanitized_uri})"
88
95
  @connection = Bunny.new(host: host, port: port, vhost: vhost,
89
96
  tls: tls, tls_key: tls_key, tls_cert: tls_cert,
@@ -140,6 +147,10 @@ module Hutch
140
147
  op && cf
141
148
  end
142
149
 
150
+ def tracing_enabled?
151
+ @config[:tracer] && @config[:tracer] != Hutch::Tracers::NullTracer
152
+ end
153
+
143
154
  # Create / get a durable queue and apply namespace if it exists.
144
155
  def queue(name, arguments = {})
145
156
  with_bunny_precondition_handler('queue') do
@@ -30,6 +30,7 @@ module Hutch
30
30
  require_paths: [],
31
31
  autoload_rails: true,
32
32
  error_handlers: [Hutch::ErrorHandlers::Logger.new],
33
+ tracer: Hutch::Tracers::NullTracer,
33
34
  namespace: nil,
34
35
  daemonise: false,
35
36
  pidfile: nil,
@@ -84,7 +85,16 @@ module Hutch
84
85
 
85
86
  def self.load_from_file(file)
86
87
  YAML.load(ERB.new(File.read(file)).result).each do |attr, value|
87
- Hutch::Config.send("#{attr}=", value)
88
+ Hutch::Config.send("#{attr}=", convert_value(attr, value))
89
+ end
90
+ end
91
+
92
+ def self.convert_value(attr, value)
93
+ case attr
94
+ when "tracer"
95
+ Kernel.const_get(value)
96
+ else
97
+ value
88
98
  end
89
99
  end
90
100
 
@@ -19,6 +19,10 @@ module Hutch
19
19
  def requeue!
20
20
  broker.requeue(delivery_info.delivery_tag)
21
21
  end
22
+
23
+ def logger
24
+ Hutch::Logging.logger
25
+ end
22
26
 
23
27
  module ClassMethods
24
28
  # Add one or more routing keys to the set of routing keys the consumer
@@ -3,5 +3,6 @@ module Hutch
3
3
  autoload :Logger, 'hutch/error_handlers/logger'
4
4
  autoload :Sentry, 'hutch/error_handlers/sentry'
5
5
  autoload :Honeybadger, 'hutch/error_handlers/honeybadger'
6
+ autoload :Airbrake, 'hutch/error_handlers/airbrake'
6
7
  end
7
8
  end
@@ -0,0 +1,26 @@
1
+ require 'hutch/logging'
2
+ require 'airbrake'
3
+
4
+ module Hutch
5
+ module ErrorHandlers
6
+ class Airbrake
7
+ include Logging
8
+
9
+ def handle(message_id, payload, consumer, ex)
10
+ prefix = "message(#{message_id || '-'}): "
11
+ logger.error prefix + "Logging event to Airbrake"
12
+ logger.error prefix + "#{ex.class} - #{ex.message}"
13
+ ::Airbrake.notify_or_ignore(ex, {
14
+ :error_class => ex.class.name,
15
+ :error_message => "#{ ex.class.name }: #{ ex.message }",
16
+ :backtrace => ex.backtrace,
17
+ :parameters => {
18
+ :payload => payload,
19
+ :consumer => consumer,
20
+ },
21
+ :cgi_data => ENV.to_hash,
22
+ })
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,5 +1,6 @@
1
1
  require 'multi_json'
2
2
  require 'forwardable'
3
+ require 'active_support/core_ext/hash/indifferent_access'
3
4
 
4
5
  module Hutch
5
6
  class Message
@@ -11,7 +12,7 @@ module Hutch
11
12
  @delivery_info = delivery_info
12
13
  @properties = properties
13
14
  @payload = payload
14
- @body = MultiJson.load(payload, symbolize_keys: true)
15
+ @body = MultiJson.load(payload).with_indifferent_access
15
16
  end
16
17
 
17
18
  def_delegator :@body, :[]
@@ -0,0 +1,6 @@
1
+ module Hutch
2
+ module Tracers
3
+ autoload :NullTracer, 'hutch/tracers/null_tracer'
4
+ autoload :NewRelic, 'hutch/tracers/newrelic'
5
+ end
6
+ end
@@ -0,0 +1,19 @@
1
+ require 'newrelic_rpm'
2
+
3
+ module Hutch
4
+ module Tracers
5
+ class NewRelic
6
+ include ::NewRelic::Agent::Instrumentation::ControllerInstrumentation
7
+
8
+ def initialize(klass)
9
+ @klass = klass
10
+ end
11
+
12
+ def handle(message)
13
+ @klass.process(message)
14
+ end
15
+
16
+ add_transaction_tracer :handle, :category => 'OtherTransaction/HutchConsumer', :path => '#{@klass.class.name}'
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ module Hutch
2
+ module Tracers
3
+ class NullTracer
4
+
5
+ def initialize(klass)
6
+ @klass = klass
7
+ end
8
+
9
+ def handle(message)
10
+ @klass.process(message)
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -1,4 +1,4 @@
1
1
  module Hutch
2
- VERSION = '0.15.0'.freeze
2
+ VERSION = '0.16.0'.freeze
3
3
  end
4
4
 
@@ -81,7 +81,8 @@ module Hutch
81
81
  broker = @broker
82
82
  begin
83
83
  message = Message.new(delivery_info, properties, payload)
84
- consumer.new.tap { |c| c.broker, c.delivery_info = @broker, delivery_info }.process(message)
84
+ consumer_instance = consumer.new.tap { |c| c.broker, c.delivery_info = @broker, delivery_info }
85
+ with_tracing(consumer_instance).handle(message)
85
86
  broker.ack(delivery_info.delivery_tag)
86
87
  rescue StandardError => ex
87
88
  broker.nack(delivery_info.delivery_tag)
@@ -89,6 +90,10 @@ module Hutch
89
90
  end
90
91
  end
91
92
 
93
+ def with_tracing(klass)
94
+ Hutch::Config[:tracer].new(klass)
95
+ end
96
+
92
97
  def handle_error(message_id, payload, consumer, ex)
93
98
  Hutch::Config[:error_handlers].each do |backend|
94
99
  backend.handle(message_id, payload, consumer, ex)
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hutch::ErrorHandlers::Airbrake do
4
+ let(:error_handler) { Hutch::ErrorHandlers::Airbrake.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 Airbrake" do
16
+ message_id = "1"
17
+ payload = "{}"
18
+ consumer = double
19
+ ex = error
20
+ message = {
21
+ :error_class => ex.class.name,
22
+ :error_message => "#{ ex.class.name }: #{ ex.message }",
23
+ :backtrace => ex.backtrace,
24
+ :parameters => {
25
+ :payload => payload,
26
+ :consumer => consumer,
27
+ },
28
+ :cgi_data => ENV.to_hash,
29
+ }
30
+ expect(::Airbrake).to receive(:notify_or_ignore).with(ex, message)
31
+ error_handler.handle(message_id, payload, consumer, ex)
32
+ end
33
+ end
34
+ end
@@ -3,7 +3,7 @@ require 'hutch/message'
3
3
  describe Hutch::Message do
4
4
  let(:delivery_info) { double('Delivery Info') }
5
5
  let(:props) { double('Properties') }
6
- let(:body) {{ foo: 'bar' }}
6
+ let(:body) {{ foo: 'bar' }.with_indifferent_access}
7
7
  let(:json_body) { MultiJson.dump(body) }
8
8
  subject(:message) { Hutch::Message.new(delivery_info, props, json_body) }
9
9
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hutch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.0
4
+ version: 0.16.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Harry Marr
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-05 00:00:00.000000000 Z
11
+ date: 2015-07-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bunny
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1.5'
55
+ - !ruby/object:Gem::Dependency
56
+ name: activesupport
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rspec
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -108,18 +122,23 @@ files:
108
122
  - lib/hutch/config.rb
109
123
  - lib/hutch/consumer.rb
110
124
  - lib/hutch/error_handlers.rb
125
+ - lib/hutch/error_handlers/airbrake.rb
111
126
  - lib/hutch/error_handlers/honeybadger.rb
112
127
  - lib/hutch/error_handlers/logger.rb
113
128
  - lib/hutch/error_handlers/sentry.rb
114
129
  - lib/hutch/exceptions.rb
115
130
  - lib/hutch/logging.rb
116
131
  - lib/hutch/message.rb
132
+ - lib/hutch/tracers.rb
133
+ - lib/hutch/tracers/newrelic.rb
134
+ - lib/hutch/tracers/null_tracer.rb
117
135
  - lib/hutch/version.rb
118
136
  - lib/hutch/worker.rb
119
137
  - spec/hutch/broker_spec.rb
120
138
  - spec/hutch/cli_spec.rb
121
139
  - spec/hutch/config_spec.rb
122
140
  - spec/hutch/consumer_spec.rb
141
+ - spec/hutch/error_handlers/airbrake_spec.rb
123
142
  - spec/hutch/error_handlers/honeybadger_spec.rb
124
143
  - spec/hutch/error_handlers/logger_spec.rb
125
144
  - spec/hutch/error_handlers/sentry_spec.rb
@@ -148,7 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
148
167
  version: '0'
149
168
  requirements: []
150
169
  rubyforge_project:
151
- rubygems_version: 2.4.5
170
+ rubygems_version: 2.4.3
152
171
  signing_key:
153
172
  specification_version: 4
154
173
  summary: Easy inter-service communication using RabbitMQ.
@@ -157,6 +176,7 @@ test_files:
157
176
  - spec/hutch/cli_spec.rb
158
177
  - spec/hutch/config_spec.rb
159
178
  - spec/hutch/consumer_spec.rb
179
+ - spec/hutch/error_handlers/airbrake_spec.rb
160
180
  - spec/hutch/error_handlers/honeybadger_spec.rb
161
181
  - spec/hutch/error_handlers/logger_spec.rb
162
182
  - spec/hutch/error_handlers/sentry_spec.rb
@@ -165,4 +185,3 @@ test_files:
165
185
  - spec/hutch/worker_spec.rb
166
186
  - spec/hutch_spec.rb
167
187
  - spec/spec_helper.rb
168
- has_rdoc: