hutch 0.14.0 → 0.15.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: 3c92582d4268b9d9623c60f4b2588d4afc244c17
4
- data.tar.gz: f783601d90dd7031c90c6a6372eb6f2b6b4ef2e4
3
+ metadata.gz: 4edfb298acf9e73fb226a3708e76d7e99ad345e3
4
+ data.tar.gz: d17eb84b63b21b42501570196abe6ef57ca94cde
5
5
  SHA512:
6
- metadata.gz: e40a52fafa102ec87c2df5e885dcffd48a0a6786b08cd4c133122e4da85a2a614aeca75513fbd4f3d464409b6d8189c8585ea4b9d456f893e44b97957ffcba0a
7
- data.tar.gz: 19f8a9dc63bf258f9b0211f49f9b21a509266a1f09eb2d3e3865d3acc2d2eb13a6fdc5d4c682accbaf98ec6d4794f1775d28156723a62e88be2b68c651e4d8bc
6
+ metadata.gz: 99ba07374f0f8bcf407ef537ea0a8342cb4368cf323c0f41deee27a37e1b6cf156dc6a72645bf2ecc6181219a0723c9c6795035d7ac3cc46ad4783f936edd516
7
+ data.tar.gz: 8a6abf7f30f6dcb3c88d968deba3115389b6a043293a75609ff5e441c94da55ac3c31d81dad4049f52710ac12bff59d4643f878ee40bac143d35b3070edf8c84
data/.travis.yml CHANGED
@@ -1,7 +1,8 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.1.0
4
- - 2.0.0
5
- - 1.9.3
3
+ - "2.2"
4
+ - "2.1"
5
+ - "2.0"
6
+ - "1.9.3"
6
7
  services:
7
8
  - rabbitmq
data/CHANGELOG.md CHANGED
@@ -1,4 +1,12 @@
1
- ## 0.14.0 — (unreleased)
1
+ ## 0.15.0 — (unreleased)
2
+
3
+ Allow to set custom arguments per consumers by using the `arguments` setter.
4
+ Arguments are usually used by rabbitmq plugins or to set queue policies. You can
5
+ find a list of supported arguments [here](https://www.rabbitmq.com/extensions.html).
6
+
7
+ Contributed by Pierre-Louis Gottfrois.
8
+
9
+ ## 0.14.0 — Feb 23rd, 2015
2
10
 
3
11
  ### Configurable Socket Timeouts
4
12
 
data/README.md CHANGED
@@ -80,6 +80,19 @@ class FailedPaymentConsumer
80
80
  end
81
81
  ```
82
82
 
83
+ You can also set custom arguments per consumer. This example declares a consumer with
84
+ a maximum length of 10 messages:
85
+
86
+ ```ruby
87
+ class FailedPaymentConsumer
88
+ include Hutch::Consumer
89
+ consume 'gc.ps.payment.failed'
90
+ arguments 'x-max-length' => 10
91
+ end
92
+ ```
93
+
94
+ Custom queue arguments can be found on [this page](https://www.rabbitmq.com/extensions.html).
95
+
83
96
  If you are using Hutch with Rails and want to make Hutch log to the Rails
84
97
  logger rather than `stdout`, add this to `config/initializers/hutch.rb`
85
98
 
@@ -134,8 +147,6 @@ mq_host: broker.yourhost.com
134
147
  Passing a setting as a command-line option will overwrite what's specified
135
148
  in the config file, allowing for easy customization.
136
149
 
137
-
138
-
139
150
  ### Loading Consumers
140
151
 
141
152
  Using Hutch with a Rails app is simple. Either start Hutch in the working
@@ -153,6 +164,20 @@ $ hutch --require path/to/rails-app # loads a rails app
153
164
  $ hutch --require path/to/file.rb # loads a ruby file
154
165
  ```
155
166
 
167
+ ### Stopping Hutch
168
+
169
+ Hutch supports graceful stops. That means that if done correctly, Hutch will wait for your consumer to finish processing before exiting.
170
+
171
+ To gracefully stop your workers, you may send the following signals to your Hutch processes: `INT`, `TERM`, or `QUIT`.
172
+
173
+ ```bash
174
+ kill -SIGINT 123 # or kill -2 123
175
+ kill -SIGTERM 456 # or kill -15 456
176
+ kill -SIGQUIT 789 # or kill -3 789
177
+ ```
178
+
179
+ ![](http://g.recordit.co/wyCdzG9Kh3.gif)
180
+
156
181
  ## Producers
157
182
 
158
183
  Hutch includes a `publish` method for sending messages to Hutch consumers. When
data/lib/hutch/broker.rb CHANGED
@@ -141,11 +141,11 @@ module Hutch
141
141
  end
142
142
 
143
143
  # Create / get a durable queue and apply namespace if it exists.
144
- def queue(name)
144
+ def queue(name, arguments = {})
145
145
  with_bunny_precondition_handler('queue') do
146
146
  namespace = @config[:namespace].to_s.downcase.gsub(/[^-_:\.\w]/, "")
147
147
  name = name.prepend(namespace + ":") unless namespace.empty?
148
- channel.queue(name, durable: true)
148
+ channel.queue(name, durable: true, arguments: arguments)
149
149
  end
150
150
  end
151
151
 
@@ -193,7 +193,12 @@ module Hutch
193
193
  end
194
194
 
195
195
  def stop
196
- @channel.work_pool.kill
196
+ # Enqueue a failing job that kills the consumer loop
197
+ channel_work_pool.shutdown
198
+ # Give `timeout` seconds to jobs that are still being processed
199
+ channel_work_pool.join(@config[:graceful_exit_timeout])
200
+ # If after `timeout` they are still running, they are killed
201
+ channel_work_pool.kill
197
202
  end
198
203
 
199
204
  def requeue(delivery_tag)
@@ -305,7 +310,11 @@ module Hutch
305
310
  end
306
311
 
307
312
  def work_pool_threads
308
- @channel.work_pool.threads || []
313
+ channel_work_pool.threads || []
314
+ end
315
+
316
+ def channel_work_pool
317
+ @channel.work_pool
309
318
  end
310
319
 
311
320
  def generate_id
data/lib/hutch/config.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'hutch/error_handlers/logger'
2
+ require 'erb'
2
3
  require 'logger'
3
4
 
4
5
  module Hutch
@@ -43,7 +44,11 @@ module Hutch
43
44
  connection_timeout: 11,
44
45
  read_timeout: 11,
45
46
  write_timeout: 11,
46
- enable_http_api_use: true
47
+ enable_http_api_use: true,
48
+ # Number of seconds that a running consumer is given
49
+ # to finish its job when gracefully exiting Hutch, before
50
+ # it's killed.
51
+ graceful_exit_timeout: 11,
47
52
  }.merge(params)
48
53
  end
49
54
 
@@ -78,7 +83,7 @@ module Hutch
78
83
  end
79
84
 
80
85
  def self.load_from_file(file)
81
- YAML.load(file).each do |attr, value|
86
+ YAML.load(ERB.new(File.read(file)).result).each do |attr, value|
82
87
  Hutch::Config.send("#{attr}=", value)
83
88
  end
84
89
  end
@@ -32,6 +32,11 @@ module Hutch
32
32
  @queue_name = name
33
33
  end
34
34
 
35
+ # Allow to specify custom arguments that will be passed when creating the queue.
36
+ def arguments(arguments = {})
37
+ @arguments = arguments
38
+ end
39
+
35
40
  # The RabbitMQ queue name for the consumer. This is derived from the
36
41
  # fully-qualified class name. Module separators are replaced with single
37
42
  # colons, camelcased class names are converted to snake case.
@@ -42,6 +47,11 @@ module Hutch
42
47
  queue_name.downcase
43
48
  end
44
49
 
50
+ # Returns consumer custom arguments.
51
+ def get_arguments
52
+ @arguments || {}
53
+ end
54
+
45
55
  # Accessor for the consumer's routing key.
46
56
  def routing_keys
47
57
  @routing_keys ||= Set.new
data/lib/hutch/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Hutch
2
- VERSION = '0.14.0'.freeze
2
+ VERSION = '0.15.0'.freeze
3
3
  end
4
4
 
data/lib/hutch/worker.rb CHANGED
@@ -62,7 +62,7 @@ module Hutch
62
62
  # Bind a consumer's routing keys to its queue, and set up a subscription to
63
63
  # receive messages sent to the queue.
64
64
  def setup_queue(consumer)
65
- queue = @broker.queue(consumer.get_queue_name)
65
+ queue = @broker.queue(consumer.get_queue_name, consumer.get_arguments)
66
66
  @broker.bind_queue(queue, consumer.routing_keys)
67
67
 
68
68
  queue.subscribe(manual_ack: true) do |delivery_info, properties, payload|
@@ -128,14 +128,16 @@ describe Hutch::Broker do
128
128
 
129
129
  describe '#queue' do
130
130
  let(:channel) { double('Channel') }
131
+ let(:arguments) { { foo: :bar } }
131
132
  before { allow(broker).to receive(:channel) { channel } }
132
133
 
133
134
  it 'applies a global namespace' do
134
135
  config[:namespace] = 'mirror-all.service'
135
136
  expect(broker.channel).to receive(:queue) do |*args|
136
- args.first == 'mirror-all.service:test'
137
+ args.first == ''
138
+ args.last == arguments
137
139
  end
138
- broker.queue('test')
140
+ broker.queue('test', arguments)
139
141
  end
140
142
  end
141
143
 
@@ -211,6 +213,25 @@ describe Hutch::Broker do
211
213
  end
212
214
  end
213
215
 
216
+ describe '#stop' do
217
+ let(:thread_1) { double('Thread') }
218
+ let(:thread_2) { double('Thread') }
219
+ let(:work_pool) { double('Bunny::ConsumerWorkPool') }
220
+ let(:config) { { graceful_exit_timeout: 2 } }
221
+
222
+ before do
223
+ allow(broker).to receive(:channel_work_pool).and_return(work_pool)
224
+ end
225
+
226
+ it 'gracefully stops the work pool' do
227
+ expect(work_pool).to receive(:shutdown)
228
+ expect(work_pool).to receive(:join).with(2)
229
+ expect(work_pool).to receive(:kill)
230
+
231
+ broker.stop
232
+ end
233
+ end
234
+
214
235
  describe '#publish' do
215
236
  context 'with a valid connection' do
216
237
  before { broker.set_up_amqp_connection }
@@ -97,4 +97,30 @@ describe Hutch::Config do
97
97
  end
98
98
  end
99
99
  end
100
+
101
+ describe '.load_from_file' do
102
+ let(:host) { 'localhost' }
103
+ let(:username) { 'calvin' }
104
+ let(:file) do
105
+ Tempfile.new('configs.yaml').tap do |t|
106
+ t.write(config_contents)
107
+ t.rewind
108
+ end
109
+ end
110
+
111
+ context 'when using ERb' do
112
+ let(:config_contents) do
113
+ <<-YAML
114
+ mq_host: 'localhost'
115
+ mq_username: '<%= "calvin" %>'
116
+ YAML
117
+ end
118
+
119
+ it 'loads in the config data' do
120
+ Hutch::Config.load_from_file(file)
121
+ expect(Hutch::Config.mq_host).to eq host
122
+ expect(Hutch::Config.mq_username).to eq username
123
+ end
124
+ end
125
+ end
100
126
  end
@@ -22,6 +22,7 @@ describe Hutch::Consumer do
22
22
  class ComplexConsumer
23
23
  include Hutch::Consumer
24
24
  consume 'hutch.test1', 'hutch.test2'
25
+ arguments foo: :bar
25
26
  end
26
27
  end
27
28
  ComplexConsumer
@@ -62,11 +63,36 @@ describe Hutch::Consumer do
62
63
  end
63
64
 
64
65
  describe '.queue_name' do
66
+ let(:queue_name) { 'foo' }
67
+
65
68
  it 'overrides the queue name' do
66
-
69
+ simple_consumer.queue_name(queue_name)
70
+ expect(simple_consumer.get_queue_name).to eq(queue_name)
67
71
  end
68
72
  end
69
73
 
74
+ describe '.arguments' do
75
+ let(:args) { { foo: :bar} }
76
+
77
+ it 'overrides the arguments' do
78
+ simple_consumer.arguments(args)
79
+ expect(simple_consumer.get_arguments).to eq(args)
80
+ end
81
+
82
+ end
83
+
84
+ describe '.get_arguments' do
85
+
86
+ context 'when defined' do
87
+ it { expect(complex_consumer.get_arguments).to eq(foo: :bar) }
88
+ end
89
+
90
+ context 'when not defined' do
91
+ it { expect(simple_consumer.get_arguments).to eq({}) }
92
+ end
93
+
94
+ end
95
+
70
96
  describe '.get_queue_name' do
71
97
 
72
98
  context 'when queue name has been set explicitly' do
@@ -3,7 +3,7 @@ require 'hutch/worker'
3
3
 
4
4
  describe Hutch::Worker do
5
5
  let(:consumer) { double('Consumer', routing_keys: %w( a b c ),
6
- get_queue_name: 'consumer') }
6
+ get_queue_name: 'consumer', get_arguments: {}) }
7
7
  let(:consumers) { [consumer, double('Consumer')] }
8
8
  let(:broker) { Hutch::Broker.new }
9
9
  subject(:worker) { Hutch::Worker.new(broker, consumers) }
@@ -23,7 +23,7 @@ describe Hutch::Worker do
23
23
  before { allow(broker).to receive_messages(queue: queue, bind_queue: nil) }
24
24
 
25
25
  it 'creates a queue' do
26
- expect(broker).to receive(:queue).with(consumer.get_queue_name).and_return(queue)
26
+ expect(broker).to receive(:queue).with(consumer.get_queue_name, consumer.get_arguments).and_return(queue)
27
27
  worker.setup_queue(consumer)
28
28
  end
29
29
 
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.14.0
4
+ version: 0.15.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-02-23 00:00:00.000000000 Z
11
+ date: 2015-05-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bunny