hutch 0.15.0 → 0.16.0

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