hutch 0.7.0 → 0.8.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: 2432ba126d871fbe57468e88a39c6d589a01aa2f
4
- data.tar.gz: 865526ad5d702eaaea80ee000b6e8ef879b5ac18
3
+ metadata.gz: 5a5e2b2315f71a38d34043446034950e26c63612
4
+ data.tar.gz: 24f650b6681c6c7c18e5a9a067666155edae4d2d
5
5
  SHA512:
6
- metadata.gz: 87d496756e3df55679391977995de5eb836a949cd80ca0ecafb7d99966512c736be01307e72976cad95fb122fcd048c51154a7456c9cfec7b1e4d2080ef9c20f
7
- data.tar.gz: 5b8f3e3fd23af0451da805d64f90ff8afc5b8ee0be93c04a4fec7be45598c32fc2ad96d59442d660974f8b3d18e47f2e507aa6988b369207721173e5e1812877
6
+ metadata.gz: ffdefefec637a9ad46fb00207a74c78210fcc167c0dbfe6c34a91da32ec5499ea67c07f12a68af1ac0ea7e9d23a9df7b33690a9c68d9a4b765897533fcc37d18
7
+ data.tar.gz: ac34de5ef0600b31a6f3614de06508cca2c47406371a9137f43458a2533996cac906a47825c45230b5bb887633dbc15b2c859fb1bae477b77149c221e5b6f198
@@ -1,6 +1,85 @@
1
- ## 0.7.0 — unreleased
1
+ ## 0.8.0 — unreleased
2
2
 
3
- - [Global properties can now be specified](https://github.com/gocardless/hutch/pull/62) for publishing
3
+ ### Uncaught Exceptions Result in Rejected Messages
4
+
5
+ Uncaught exceptions in consumers now result in Hutch rejecting
6
+ messages (deliveries) using `basic.nack`. This way they are [dead lettered](http://www.rabbitmq.com/dlx.html).
7
+
8
+ Contributed by Garrett Johnson.
9
+
10
+ ### Missing Require
11
+
12
+ `hutch/consumer.rb` no longer fails to load with the
13
+ apps that do not `require "set"`.
14
+
15
+ ### Relaxed Queue Namespace Validation
16
+
17
+ Namespaces now can include any characters that are valid in RabbitMQ
18
+ queue names.
19
+
20
+ Contributed by Garrett Johnson.
21
+
22
+ ### basic.qos Configuration
23
+
24
+ It is now possible to configure `basic.qos` (aka channel prefetch) setting
25
+ used by Hutch using the `:channel_prefetch` config key.
26
+
27
+ ### Passwords No Longer Logged
28
+
29
+ Hutch now elides passwords from logs.
30
+
31
+
32
+ ## 0.7.0 — January 14, 2014
33
+
34
+ ### Optional HTTP API Use
35
+
36
+ It is now possible to make Hutch [not use RabbitMQ HTTP
37
+ API](https://github.com/gocardless/hutch/pull/69) (e.g. when the
38
+ RabbitMQ management plugin that provides it is not available).
39
+
40
+
41
+ ### Extra Arguments for Hutch::Broker#publish
42
+
43
+ Extra options [passed to `Hutch::Broker#publish` will now be propagated](https://github.com/gocardless/hutch/pull/61).
44
+
45
+
46
+ ### Content-Type for Messages
47
+
48
+ Messages published with Hutch now have content type set
49
+ to `application/json`.
50
+
51
+
52
+ ### Greater Heartbeat Interval
53
+
54
+ Hutch now uses heartbeat interval of 30, so heartbeats won't interfere with transfers
55
+ of large messages over high latency networks (e.g. between AWS availability regions).
56
+
57
+
58
+ ### Custom Queue Names
59
+
60
+ It is now possible to [specify an optional queue name](https://github.com/gocardless/hutch/pull/49):
61
+
62
+ ``` ruby
63
+ class FailedPaymentConsumer
64
+ include Hutch::Consumer
65
+ consume 'gc.ps.payment.failed'
66
+ queue_name 'failed_payments'
67
+
68
+ def process(message)
69
+ mark_payment_as_failed(message[:id])
70
+ end
71
+ end
72
+ ```
73
+
74
+ ### Global Properties for Publishers
75
+
76
+ [Global properties can now be specified](https://github.com/gocardless/hutch/pull/62) for publishing:
77
+
78
+ ``` ruby
79
+ Hutch.global_properties = proc {
80
+ { app_id: 'api', headers: { request_id: RequestId.request_id } }
81
+ }
82
+ ```
4
83
 
5
84
  ## 0.6.0 - November 4, 2013
6
85
 
@@ -1,7 +1,7 @@
1
1
  require File.expand_path('../lib/hutch/version', __FILE__)
2
2
 
3
3
  Gem::Specification.new do |gem|
4
- gem.add_runtime_dependency 'bunny', '~> 1.1.0'
4
+ gem.add_runtime_dependency 'bunny', '~> 1.1.2'
5
5
  gem.add_runtime_dependency 'carrot-top', '~> 0.0.7'
6
6
  gem.add_runtime_dependency 'multi_json', '~> 1.5'
7
7
  gem.add_development_dependency 'rspec', '~> 2.12.0'
@@ -55,9 +55,8 @@ module Hutch
55
55
  tls_key = @config[:mq_tls_cert]
56
56
  tls_cert = @config[:mq_tls_key]
57
57
  protocol = tls ? "amqps://" : "amqp://"
58
- uri = "#{username}:#{password}@#{host}:#{port}/#{vhost.sub(/^\//, '')}"
59
- sanitized_uri = "#{protocol}#{host}:#{port}"
60
- logger.info "connecting to rabbitmq (#{protocol}#{uri})"
58
+ sanitized_uri = "#{protocol}#{username}@#{host}:#{port}/#{vhost.sub(/^\//, '')}"
59
+ logger.info "connecting to rabbitmq (#{sanitized_uri})"
61
60
 
62
61
  @connection = Bunny.new(host: host, port: port, vhost: vhost,
63
62
  tls: tls, tls_key: tls_key, tls_cert: tls_cert,
@@ -74,14 +73,16 @@ module Hutch
74
73
 
75
74
  def open_channel!
76
75
  logger.info 'opening rabbitmq channel'
77
- @channel = connection.create_channel
76
+ @channel = connection.create_channel.tap do |ch|
77
+ ch.prefetch(@config[:channel_prefetch]) if @config[:channel_prefetch]
78
+ end
78
79
  end
79
80
 
80
81
  # Set up the connection to the RabbitMQ management API. Unfortunately, this
81
82
  # is necessary to do a few things that are impossible over AMQP. E.g.
82
83
  # listing queues and bindings.
83
84
  def set_up_api_connection
84
- logger.info "connecting to rabbitmq management api (#{api_config.management_uri})"
85
+ logger.info "connecting to rabbitmq HTTP API (#{api_config.sanitized_uri})"
85
86
 
86
87
  with_authentication_error_handler do
87
88
  with_connection_error_handler do
@@ -96,7 +97,7 @@ module Hutch
96
97
  # Create / get a durable queue and apply namespace if it exists.
97
98
  def queue(name)
98
99
  with_bunny_precondition_handler('queue') do
99
- namespace = @config[:namespace].to_s.downcase.gsub(/\W|:/, "")
100
+ namespace = @config[:namespace].to_s.downcase.gsub(/[^-_:\.\w]/, "")
100
101
  name = name.prepend(namespace + ":") unless namespace.empty?
101
102
  channel.queue(name, durable: true)
102
103
  end
@@ -151,6 +152,10 @@ module Hutch
151
152
  @channel.ack(delivery_tag, false)
152
153
  end
153
154
 
155
+ def nack(delivery_tag)
156
+ @channel.nack(delivery_tag, false, false)
157
+ end
158
+
154
159
  def publish(routing_key, message, properties = {})
155
160
  ensure_connection!(routing_key, message)
156
161
 
@@ -189,16 +194,16 @@ module Hutch
189
194
  config.password = @config[:mq_password]
190
195
  config.ssl = @config[:mq_api_ssl]
191
196
  config.protocol = config.ssl ? "https://" : "http://"
192
- config.management_uri = "#{config.protocol}#{config.username}:#{config.password}@#{config.host}:#{config.port}/"
197
+ config.sanitized_uri = "#{config.protocol}#{config.username}@#{config.host}:#{config.port}/"
193
198
  end
194
199
  end
195
200
 
196
201
  def with_authentication_error_handler
197
202
  yield
198
203
  rescue Net::HTTPServerException => ex
199
- logger.error "api connection error: #{ex.message.downcase}"
204
+ logger.error "HTTP API connection error: #{ex.message.downcase}"
200
205
  if ex.response.code == '401'
201
- raise AuthenticationError.new('invalid api credentials')
206
+ raise AuthenticationError.new('invalid HTTP API credentials')
202
207
  else
203
208
  raise
204
209
  end
@@ -207,15 +212,15 @@ module Hutch
207
212
  def with_connection_error_handler
208
213
  yield
209
214
  rescue Errno::ECONNREFUSED => ex
210
- logger.error "api connection error: #{ex.message.downcase}"
211
- raise ConnectionError.new("couldn't connect to api at #{api_config.management_uri}")
215
+ logger.error "HTTP API connection error: #{ex.message.downcase}"
216
+ raise ConnectionError.new("couldn't connect to HTTP API at #{api_config.sanitized_uri}")
212
217
  end
213
218
 
214
219
  def with_bunny_precondition_handler(item)
215
220
  yield
216
221
  rescue Bunny::PreconditionFailed => ex
217
222
  logger.error ex.message
218
- s = "RabbitMQ responded with Precondition Failed when creating this #{item}. " +
223
+ s = "RabbitMQ responded with 406 Precondition Failed when creating this #{item}. " +
219
224
  "Perhaps it is being redeclared with non-matching attributes"
220
225
  raise WorkerSetupError.new(s)
221
226
  end
@@ -25,7 +25,8 @@ module Hutch
25
25
  require_paths: [],
26
26
  autoload_rails: true,
27
27
  error_handlers: [Hutch::ErrorHandlers::Logger.new],
28
- namespace: nil
28
+ namespace: nil,
29
+ channel_prefetch: 0
29
30
  }
30
31
  end
31
32
 
@@ -1,3 +1,5 @@
1
+ require 'set'
2
+
1
3
  module Hutch
2
4
  # Include this module in a class to register it as a consumer. Consumers
3
5
  # gain a class method called `consume`, which should be used to register
@@ -1,4 +1,4 @@
1
1
  module Hutch
2
- VERSION = '0.7.0'.freeze
2
+ VERSION = '0.8.0'.freeze
3
3
  end
4
4
 
@@ -85,7 +85,7 @@ module Hutch
85
85
  broker.ack(delivery_info.delivery_tag)
86
86
  rescue StandardError => ex
87
87
  handle_error(properties.message_id, consumer, ex)
88
- broker.ack(delivery_info.delivery_tag)
88
+ broker.nack(delivery_info.delivery_tag)
89
89
  end
90
90
  end
91
91
 
@@ -97,8 +97,7 @@ module Hutch
97
97
 
98
98
  def consumers=(val)
99
99
  if val.empty?
100
- logger.warn 'no consumer loaded, ensure there\'s' +
101
- 'no configuration issue'
100
+ logger.warn "no consumer loaded, ensure there's no configuration issue"
102
101
  end
103
102
  @consumers = val
104
103
  end
@@ -58,6 +58,17 @@ describe Hutch::Broker do
58
58
 
59
59
  specify { set_up_amqp_connection.should raise_error }
60
60
  end
61
+
62
+ context 'with channel_prefetch set' do
63
+ let(:prefetch_value) { 1 }
64
+ before { config[:channel_prefetch] = prefetch_value }
65
+ after { broker.disconnect }
66
+
67
+ it "set's channel's prefetch" do
68
+ Bunny::Channel.any_instance.should_receive(:prefetch).with(prefetch_value)
69
+ broker.set_up_amqp_connection
70
+ end
71
+ end
61
72
  end
62
73
 
63
74
  describe '#set_up_api_connection', rabbitmq: true do
@@ -82,8 +93,8 @@ describe Hutch::Broker do
82
93
  before { broker.stub(:channel) { channel } }
83
94
 
84
95
  it 'applies a global namespace' do
85
- config[:namespace] = 'service'
86
- broker.channel.should_receive(:queue).with { |*args| args.first == 'service:test' }
96
+ config[:namespace] = 'mirror-all.service'
97
+ broker.channel.should_receive(:queue).with { |*args| args.first == 'mirror-all.service:test' }
87
98
  broker.queue('test')
88
99
  end
89
100
  end
@@ -108,7 +119,7 @@ describe Hutch::Broker do
108
119
  end
109
120
 
110
121
  describe '#bind_queue' do
111
-
122
+
112
123
  around { |example| broker.connect { example.run } }
113
124
 
114
125
  let(:routing_keys) { %w( a b c ) }
@@ -47,6 +47,7 @@ describe Hutch::Worker do
47
47
  let(:properties) { double('Properties', message_id: nil) }
48
48
  before { consumer.stub(new: consumer_instance) }
49
49
  before { broker.stub(:ack) }
50
+ before { broker.stub(:nack) }
50
51
 
51
52
  it 'passes the message to the consumer' do
52
53
  consumer_instance.should_receive(:process).
@@ -70,8 +71,8 @@ describe Hutch::Worker do
70
71
  worker.handle_message(consumer, delivery_info, properties, payload)
71
72
  end
72
73
 
73
- it 'acknowledges the message' do
74
- broker.should_receive(:ack).with(delivery_info.delivery_tag)
74
+ it 'rejects the message' do
75
+ broker.should_receive(:nack).with(delivery_info.delivery_tag)
75
76
  worker.handle_message(consumer, delivery_info, properties, payload)
76
77
  end
77
78
  end
@@ -86,8 +87,8 @@ describe Hutch::Worker do
86
87
  worker.handle_message(consumer, delivery_info, properties, payload)
87
88
  end
88
89
 
89
- it 'acknowledges the message' do
90
- broker.should_receive(:ack).with(delivery_info.delivery_tag)
90
+ it 'rejects the message' do
91
+ broker.should_receive(:nack).with(delivery_info.delivery_tag)
91
92
  worker.handle_message(consumer, delivery_info, properties, payload)
92
93
  end
93
94
  end
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.7.0
4
+ version: 0.8.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: 2014-01-14 00:00:00.000000000 Z
11
+ date: 2014-02-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bunny
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ~>
18
18
  - !ruby/object:Gem::Version
19
- version: 1.1.0
19
+ version: 1.1.2
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ~>
25
25
  - !ruby/object:Gem::Version
26
- version: 1.1.0
26
+ version: 1.1.2
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: carrot-top
29
29
  requirement: !ruby/object:Gem::Requirement