hutch 0.10.0 → 0.11.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: 803369cb7619eae888379612cf278d49133a3f68
4
- data.tar.gz: 4eb4a16d6b7a12441b9e56d972ebcc413b5fec82
3
+ metadata.gz: b4ae8b34c445db665d717e7c4b935ae246c793c4
4
+ data.tar.gz: d92e37a658a7a46a08500cf7c14589f7f6df2a17
5
5
  SHA512:
6
- metadata.gz: 3f557376e9db220197b6f6f99cd28621593ed3a5f0bc96e26c471fb40b7b54e3f79564cad661873b223c7688713112bbf5536b705efdb0d3aa4b86d88725cd6b
7
- data.tar.gz: d497420735d0567a167290a9de4130d66635f4ef36d5b1f674ca77e0320956518014cbc91054d72b10dc16ef3c2edc5498e47dd7a1b6ddce4edb013a757158ff
6
+ metadata.gz: 149952fbd91217d9bb7a92c7eac65607b45af0b35aaf0bba3424996376fa0f49fd205efc02b67e5b6a7f7a7a66a1dd22ad0e35ad576772905b0d91dc9da62950
7
+ data.tar.gz: 6a128089af08c252778bf0cef44cfbbc522aea4938c7a4904c9ea74e21528fc13559a3ecb5011700c36a4e87bdd9b98e171593a3e28829312d3b9162c9774d7e
@@ -1,14 +1,73 @@
1
- ## 0.10.0 — unreleased
1
+ ## 0.11.0 — unreleased
2
+
3
+ ### Publisher Confirms Support
4
+
5
+ `:force_publisher_confirms` is a new configuration option that forces `Hutch.publish` to wait
6
+ for a confirm for every message published. Note that this **will cause a significant drop in throughput**.
7
+
8
+ `Hutch::Broker#confirm_select` and `Hutch::Broker#wait_for_confirms` are new public API methods
9
+ that delegate to their respective `Bunny::Channel` counterparts. `Hutch::Broker#confirm_select`
10
+ can be used to handle confirms with a callback instead of waiting:
11
+
12
+ ``` ruby
13
+ broker.confirm_select do |delivery_tag, multiple, nack|
14
+ # ...
15
+ end
16
+ ```
17
+
2
18
 
3
19
  ### Bunny Update
4
20
 
5
- Bunny is updated to `1.4.x`.
21
+ Bunny is updated to [1.6.0](http://blog.rubyrabbitmq.info/blog/2014/10/31/bunny-1-dot-6-0-is-released/).
22
+
23
+
24
+ ## 0.10.0 — Oct 22, 2014
25
+
26
+ ### Configuration via URI
27
+
28
+ Hutch now supports a new configuration key, `:uri`, which allows
29
+ connection configuration via a URI.
30
+
31
+ Note that since the URI has to include credentials, this option
32
+ is not available on the command line.
33
+
34
+ ### Bunny Update
35
+
36
+ Bunny is updated to `1.5.1`, which mitigates the POODLE attack
37
+ by disabling SSL 3.0 where possible.
38
+
39
+ ### Payload in Error Handlers
40
+
41
+ Error handlers will now have access to message payload.
42
+
43
+ Contributed by Daniel Farrell.
6
44
 
7
45
  ### Exceptions in Error Handlers Don't Prevent Nacks
8
46
 
9
47
  Exceptions in error handlers no longer prevent messages from being
10
48
  `basic.nack`-ed.
11
49
 
50
+ ### Pid File Support
51
+
52
+ `:pidfile` is a new configuration option that stores Hutch process
53
+ PID in a file at provided path.
54
+
55
+ Contributed by Rustam Sharshenov.
56
+
57
+ ### More Info on Message
58
+
59
+ Bunny's `delivery_info`, `properties` and payload are now accessible on `Hutch::Message`.
60
+
61
+ Contributed by gregory.
62
+
63
+
64
+ ### Optional Config Parameters
65
+
66
+ `Hutch::Config` constructor now accepts an extra hash of optional
67
+ configuration parameters.
68
+
69
+ Contributed by Ignazio Mostallino.
70
+
12
71
 
13
72
  ## 0.9.0 — May 13, 2014
14
73
 
data/README.md CHANGED
@@ -26,6 +26,10 @@ over RabbitMQ. Hutch is opinionated: it uses topic exchanges for message
26
26
  distribution and makes some assumptions about how consumers and publishers
27
27
  should work.
28
28
 
29
+ With Hutch, consumers are stored in separate files and include the `Hutch::Consumer` module.
30
+ They are then loaded by a command line runner which connects to RabbitMQ, sets up queues and bindings,
31
+ and so on. Publishers connect to RabbitMQ via `Hutch.connect` and publish using `Hutch.publish`.
32
+
29
33
  Hutch uses [Bunny](http://rubybunny.info) under the hood.
30
34
 
31
35
 
@@ -160,6 +164,26 @@ Hutch.connect
160
164
  Hutch.publish('routing.key', subject: 'payment', action: 'received')
161
165
  ```
162
166
 
167
+ ### Producer Configuration
168
+
169
+ Producers are not run with the 'hutch' command. You can specify configuration
170
+ options as follows:
171
+
172
+ ```ruby
173
+ Hutch::Config.set(:mq_exchange, 'name')
174
+ ```
175
+
176
+ ### Publisher Confirms
177
+
178
+ For maximum message reliability when producing messages, you can force Hutch to use
179
+ [Publisher Confirms](https://www.rabbitmq.com/confirms.html) and wait for a confirmation
180
+ after every message published. This is the safest possible option for publishers
181
+ but also results in a **significant throughput drop**.
182
+
183
+ ```ruby
184
+ Hutch::Config.set(:force_publisher_confirms, true)
185
+ ```
186
+
163
187
  ### Writing Well-Behaved Publishers
164
188
 
165
189
  You may need to send messages to Hutch from languages other than Ruby. This
@@ -174,11 +198,8 @@ send messages to Hutch.
174
198
  - Use message routing keys that match those used in your Hutch consumers.
175
199
  - Be sure your exchanges are marked as durable. In the Ruby AMQP gem, this is
176
200
  done by passing `durable: true` to the exchange creation method.
177
- - Mark your messages as persistent. This is done by passing `persistent: true`
178
- to the publish method in Ruby AMQP.
179
- - Wrapping publishing code in transactions or using publisher confirms is
180
- highly recommended. This can be slightly tricky, see [this issue][pc-issue]
181
- and [this gist][pc-gist] for more info.
201
+ - Publish messages as persistent.
202
+ - Using publisher confirms is highly recommended.
182
203
 
183
204
  Here's an example of a well-behaved publisher, minus publisher confirms:
184
205
 
@@ -192,15 +213,42 @@ AMQP.connect(host: config[:host]) do |connection|
192
213
  end
193
214
  ```
194
215
 
216
+ If using publisher confirms with amqp gem, see [this issue][pc-issue]
217
+ and [this gist][pc-gist] for more info.
218
+
219
+ ## Configuration Reference
220
+
221
+ ### Config File
222
+
223
+ It is recommended to use a separate config file, unless you use URIs for connection (see below).
224
+
225
+ Known configuration parameters are:
226
+
227
+ * `mq_host`: RabbitMQ hostname (default: `localhost`)
228
+ * `mq_port`: RabbitMQ port (default: `5672`)
229
+ * `mq_vhost`: vhost to use (default: `/`)
230
+ * `mq_username`: username to use (default: `guest`, only can connect from localhost as of RabbitMQ 3.3.0)
231
+ * `mq_password`: password to use (default: `guest`)
232
+ * `mq_tls`: should TLS be used? (default: `false`)
233
+ * `mq_tls_cert`: path to client TLS certificate (public key)
234
+ * `mq_tls_key`: path to client TLS private key
235
+ * `require_paths`: array of paths to require
236
+ * `autoload_rails`: should Hutch command line runner try to automatically load Rails environment files?
237
+ * `daemonise`: should Hutch runner process daemonise?
238
+ * `pidfile`: path to PID file the runner should use
239
+ * `channel_prefetch`: basic.qos prefetch value to use (default: `0`, no limit). See Bunny and RabbitMQ documentation.
240
+ * `publisher_confirms`: enables publisher confirms. Leaves it up to the app how they are
241
+ tracked (e.g. using `Hutch::Broker#confirm_select` callback or `Hutch::Broker#wait_for_confirms`)
242
+ * `force_publisher_confirms`: enables publisher confirms, forces `Hutch::Broker#wait_for_confirms` for every publish. **This is the safest option which also offers the lowest throughput**.
243
+ * `log_level`: log level used by the standard Ruby logger (default: `Logger::INFO`)
244
+ * `mq_exchange`: exchange to use for publishing (default: `hutch`)
245
+
246
+
195
247
  ## Supported RabbitMQ Versions
196
248
 
197
249
  Hutch requires RabbitMQ 2.x or later. 3.x releases
198
250
  are recommended.
199
251
 
200
-
201
- [pc-issue]: https://github.com/ruby-amqp/amqp/issues/92
202
- [pc-gist]: https://gist.github.com/3042381
203
-
204
252
  ---
205
253
 
206
254
  GoCardless ♥ open source. If you do too, come [join us](https://gocardless.com/jobs/backend_developer).
@@ -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.5.1'
4
+ gem.add_runtime_dependency 'bunny', '>= 1.6.1'
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', '~> 3.0'
@@ -37,6 +37,13 @@ module Hutch
37
37
  end
38
38
  end
39
39
 
40
+ def self.disconnect
41
+ if @broker
42
+ @broker.disconnect
43
+ @connected = false
44
+ end
45
+ end
46
+
40
47
  def self.broker
41
48
  @broker
42
49
  end
@@ -88,6 +88,10 @@ module Hutch
88
88
  logger.info 'opening rabbitmq channel'
89
89
  @channel = connection.create_channel.tap do |ch|
90
90
  ch.prefetch(@config[:channel_prefetch]) if @config[:channel_prefetch]
91
+ if @config[:publisher_confirms] || @config[:force_publisher_confirms]
92
+ logger.info 'enabling publisher confirms'
93
+ ch.confirm_select
94
+ end
91
95
  end
92
96
  end
93
97
 
@@ -188,10 +192,26 @@ module Hutch
188
192
  properties[:message_id] ||= generate_id
189
193
 
190
194
  logger.info("publishing message '#{message.inspect}' to #{routing_key}")
191
- @exchange.publish(JSON.dump(message), {persistent: true}.
195
+
196
+ response = @exchange.publish(JSON.dump(message), {persistent: true}.
192
197
  merge(properties).
193
198
  merge(global_properties).
194
199
  merge(non_overridable_properties))
200
+
201
+ channel.wait_for_confirms if @config[:force_publisher_confirms]
202
+ response
203
+ end
204
+
205
+ def confirm_select(*args)
206
+ @channel.confirm_select(*args)
207
+ end
208
+
209
+ def wait_for_confirms
210
+ @channel.wait_for_confirms
211
+ end
212
+
213
+ def using_publisher_confirmations?
214
+ @channel.using_publisher_confirmations?
195
215
  end
196
216
 
197
217
  private
@@ -31,7 +31,13 @@ module Hutch
31
31
  namespace: nil,
32
32
  daemonise: false,
33
33
  pidfile: nil,
34
- channel_prefetch: 0
34
+ channel_prefetch: 0,
35
+ # enables publisher confirms, leaves it up to the app
36
+ # how they are tracked
37
+ publisher_confirms: false,
38
+ # like `publisher_confirms` above but also
39
+ # forces waiting for a confirm for every publish
40
+ force_publisher_confirms: false
35
41
  }.merge(params)
36
42
  end
37
43
 
@@ -61,6 +67,10 @@ module Hutch
61
67
  @config
62
68
  end
63
69
 
70
+ def self.to_hash
71
+ self.user_config
72
+ end
73
+
64
74
  def self.load_from_file(file)
65
75
  YAML.load(file).each do |attr, value|
66
76
  Hutch::Config.send("#{attr}=", value)
@@ -1,4 +1,4 @@
1
1
  module Hutch
2
- VERSION = '0.10.0'.freeze
2
+ VERSION = '0.11.0'.freeze
3
3
  end
4
4
 
@@ -65,7 +65,7 @@ module Hutch
65
65
  queue = @broker.queue(consumer.get_queue_name)
66
66
  @broker.bind_queue(queue, consumer.routing_keys)
67
67
 
68
- queue.subscribe(ack: true) do |delivery_info, properties, payload|
68
+ queue.subscribe(manual_ack: true) do |delivery_info, properties, payload|
69
69
  handle_message(consumer, delivery_info, properties, payload)
70
70
  end
71
71
  end
@@ -92,6 +92,18 @@ describe Hutch::Broker do
92
92
  broker.set_up_amqp_connection
93
93
  end
94
94
  end
95
+
96
+ context 'with force_publisher_confirms set' do
97
+ let(:force_publisher_confirms_value) { true }
98
+ before { config[:force_publisher_confirms] = force_publisher_confirms_value }
99
+ after { broker.disconnect }
100
+
101
+ it 'waits for confirmation' do
102
+ expect_any_instance_of(Bunny::Channel).
103
+ to receive(:confirm_select)
104
+ broker.set_up_amqp_connection
105
+ end
106
+ end
95
107
  end
96
108
 
97
109
  describe '#set_up_api_connection', rabbitmq: true do
@@ -252,6 +264,28 @@ describe Hutch::Broker do
252
264
  end
253
265
  end
254
266
  end
267
+
268
+ context 'with force_publisher_confirms not set in the config' do
269
+ it 'does not wait for confirms on the channel' do
270
+ expect_any_instance_of(Bunny::Channel).
271
+ to_not receive(:wait_for_confirms)
272
+ broker.publish('test.key', 'message')
273
+ end
274
+ end
275
+
276
+ context 'with force_publisher_confirms set in the config' do
277
+ let(:force_publisher_confirms_value) { true }
278
+
279
+ before do
280
+ config[:force_publisher_confirms] = force_publisher_confirms_value
281
+ end
282
+
283
+ it 'waits for confirms on the channel' do
284
+ expect_any_instance_of(Bunny::Channel).
285
+ to receive(:wait_for_confirms)
286
+ broker.publish('test.key', 'message')
287
+ end
288
+ end
255
289
  end
256
290
 
257
291
  context 'without a valid connection' do
@@ -33,7 +33,7 @@ describe Hutch::Worker do
33
33
  end
34
34
 
35
35
  it 'sets up a subscription' do
36
- expect(queue).to receive(:subscribe).with(ack: true)
36
+ expect(queue).to receive(:subscribe).with(manual_ack: true)
37
37
  worker.setup_queue(consumer)
38
38
  end
39
39
  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.10.0
4
+ version: 0.11.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-10-22 00:00:00.000000000 Z
11
+ date: 2014-11-14 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.5.1
19
+ version: 1.6.1
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.5.1
26
+ version: 1.6.1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: carrot-top
29
29
  requirement: !ruby/object:Gem::Requirement