Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow specifying an optional queue namespace #49

Merged
merged 7 commits into from
Jan 13, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,21 @@ class FailedPaymentConsumer
end
```

By default, the queue name will be named using the consumer class. You can set
the queue name explicitly by using the `queue_name` method:

```ruby
class FailedPaymentConsumer
include Hutch::Consumer
consume 'gc.ps.payment.failed'
queue_name 'failed_payments'

def process(message)
mark_payment_as_failed(message[:id])
end
end
```

If you are using Hutch with Rails and want to make Hutch log to the Rails
logger rather than `stdout`, add this to `config/initializers/hutch.rb`

Expand Down
6 changes: 4 additions & 2 deletions lib/hutch/broker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,12 @@ def set_up_api_connection
end
end

# Create / get a durable queue.
# Create / get a durable queue and apply namespace if it exists.
def queue(name)
with_bunny_precondition_handler('queue') do
@channel.queue(name, durable: true)
namespace = @config[:namespace].to_s.downcase.gsub(/\W|:/, "")
name = name.prepend(namespace + ":") unless namespace.empty?
channel.queue(name, durable: true)
end
end

Expand Down
4 changes: 4 additions & 0 deletions lib/hutch/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,10 @@ def parse_options(args = ARGV)
Hutch::Config.log_level = Logger::DEBUG
end

opts.on('--namespace NAMESPACE', 'Queue namespace') do |namespace|
Hutch::Config.namespace = namespace
end

opts.on('--version', 'Print the version and exit') do
puts "hutch v#{VERSION}"
exit 0
Expand Down
3 changes: 2 additions & 1 deletion lib/hutch/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ def self.initialize
log_level: Logger::INFO,
require_paths: [],
autoload_rails: true,
error_handlers: [Hutch::ErrorHandlers::Logger.new]
error_handlers: [Hutch::ErrorHandlers::Logger.new],
namespace: nil
}
end

Expand Down
11 changes: 9 additions & 2 deletions lib/hutch/consumer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,19 @@ def consume(*routing_keys)
@routing_keys = self.routing_keys.union(routing_keys)
end

# Explicitly set the queue name
def queue_name(name)
@queue_name = name
end

# The RabbitMQ queue name for the consumer. This is derived from the
# fully-qualified class name. Module separators are replaced with single
# colons, camelcased class names are converted to snake case.
def queue_name
def get_queue_name
return @queue_name unless @queue_name.nil?
queue_name = self.name.gsub(/::/, ':')
queue_name.gsub(/([^A-Z:])([A-Z])/) { "#{$1}_#{$2}" }.downcase
queue_name.gsub!(/([^A-Z:])([A-Z])/) { "#{$1}_#{$2}" }
queue_name.downcase
end

# Accessor for the consumer's routing key.
Expand Down
2 changes: 1 addition & 1 deletion lib/hutch/worker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def setup_queues
# Bind a consumer's routing keys to its queue, and set up a subscription to
# receive messages sent to the queue.
def setup_queue(consumer)
queue = @broker.queue(consumer.queue_name)
queue = @broker.queue(consumer.get_queue_name)
@broker.bind_queue(queue, consumer.routing_keys)

queue.subscribe(ack: true) do |delivery_info, properties, payload|
Expand Down
13 changes: 13 additions & 0 deletions spec/hutch/broker_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,17 @@
end
end

describe '#queue' do
let(:channel) { double('Channel') }
before { broker.stub(:channel) { channel } }

it 'applies a global namespace' do
config[:namespace] = 'service'
broker.channel.should_receive(:queue).with { |*args| args.first == 'service:test' }
broker.queue('test')
end
end

describe '#bindings', rabbitmq: true do
around { |example| broker.connect { example.run } }
subject { broker.bindings }
Expand All @@ -97,7 +108,9 @@
end

describe '#bind_queue' do

around { |example| broker.connect { example.run } }

let(:routing_keys) { %w( a b c ) }
let(:queue) { double('Queue', bind: nil, unbind: nil, name: 'consumer') }
before { broker.stub(bindings: { 'consumer' => ['d'] }) }
Expand Down
38 changes: 29 additions & 9 deletions spec/hutch/consumer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,22 +58,42 @@ class ComplexConsumer
end

describe '.queue_name' do
it 'replaces module separators with colons' do
module Foo
class Bar
it 'overrides the queue name' do

end
end

describe '.get_queue_name' do

context 'when queue name has been set explicitly' do
it 'returns the give queue name' do
class Foo
include Hutch::Consumer
queue_name "bar"
end
end

Foo::Bar.queue_name.should == 'foo:bar'
Foo.get_queue_name.should == "bar"
end
end

it 'converts camelcase class names to snake case' do
class FooBarBAZ
include Hutch::Consumer
context 'when no queue name has been set' do
it 'replaces module separators with colons' do
module Foo
class Bar
include Hutch::Consumer
end
end

Foo::Bar.get_queue_name.should == 'foo:bar'
end

FooBarBAZ.queue_name.should == 'foo_bar_baz'
it 'converts camelcase class names to snake case' do
class FooBarBAZ
include Hutch::Consumer
end

FooBarBAZ.get_queue_name.should == 'foo_bar_baz'
end
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions spec/hutch/worker_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
describe Hutch::Worker do
before { Raven.as_null_object }
let(:consumer) { double('Consumer', routing_keys: %w( a b c ),
queue_name: 'consumer') }
get_queue_name: 'consumer') }
let(:consumers) { [consumer, double('Consumer')] }
let(:broker) { Hutch::Broker.new }
subject(:worker) { Hutch::Worker.new(broker, consumers) }
Expand All @@ -24,7 +24,7 @@
before { broker.stub(queue: queue, bind_queue: nil) }

it 'creates a queue' do
broker.should_receive(:queue).with(consumer.queue_name).and_return(queue)
broker.should_receive(:queue).with(consumer.get_queue_name).and_return(queue)
worker.setup_queue(consumer)
end

Expand Down