“...I've been working since 2008 with Ruby / Ruby on Rails, love a bit of Elixir / Phoenix and learning Rust. I also poke through other people's code and make PRs for OpenSource Ruby projects that sometimes make it. Currently working for InPay...”

Rob Lacey (contact@robl.me)
Senior Software Engineer, Brighton, UK

Bunny Consumer

No, not something that eats bunnies. I wanted to know if I could easily run a RabbitMQ consumer that just sat there listening. It seems incorrect to have a loop sat there just doing nothing all the time but I guess it the connection is open then it should just sit there, if not it can stop and have forty winks.

Gemfile

source 'https://rubygems.org'

gem 'bunny'
gem 'pry'
gem 'pry-coolline'

gimmick.rb

require 'rubygems'
# ENV['BUNDLE_GEMFILE'] ||= File.expand_path('Gemfile', __dir__)
require 'bundler/setup'
Bundler.require(:default)

conn = Bunny.new
conn.start
# open a channel
ch = conn.create_channel

# declare a queue
q = ch.queue('test1')

q.subscribe do |_, _, payload|
  Thread.new do
    puts "payload #{payload}"
    sleep(5)
    puts "finished sleeping"
  end
end

while conn.status == :open do
  # nothing is happening here
end

As expected, when an event occurs the subscribe block is called and the payload is send to STDOUT. Wait five seconds and finish. Had I not added Thread.new consumer would have waited 5 seconds and order is not quaranteed.

Robs-iMac:consumer roblacey$ ruby gimmick.rb 
payload 2
payload 1
payload 4
payload 3
payload 5
finished sleeping
finished sleeping
finished sleeping
finished sleeping
finished sleeping

Interesting to note that when using manual_ack. Events are not automatically re-read from the queue until a new connection is made if the job is not ack’ed.

q.subscribe(manual_ack: true) do |delivery_info, _, payload|
  Thread.new do
    puts "payload #{payload} - Redelivered #{delivery_info.redelivered?}\n"
    sleep(5)
    puts "finished sleeping #{payload}\n"
    puts payload.class
    ch.acknowledge(delivery_info.delivery_tag, false) unless payload == '1' && !delivery_info.redelivered?
  end
end

while conn.status == :open do
  # nothing is happening here
end