I am trying to build RPC by using rabbitmq.
According to the tutorial for building RPC through rabbitmq http://www.rabbitmq.com/tutorials/tutorial-six-ruby.html, we can use the one reply-queue for each client and use correlation_id to map the response and request. I am confused about how the correlation_id is used?
Here is the issue I am running with, I would like to create two rpc calls synchronously from one client, using the same reply-queue with two different correlation id. However I don't know if this is the correct use case, since from what I read in the tutorial it seems to assume that each client is making the rpc call sequentially. (In this case, it becomes more confusing that why would we need the correlation_id here).
Here is the code example (the rpc_server.rb will be the same as the tutorial), for what I am trying to achieve. Hopefully it makes my question more clear.
The code block below wouldn't work, since the correlation_id is being overwrite by thr2 when we set it in thr1.
I wonder if there is anyway to modify it, to make it work? If we try to move the @reply_queue.subscribe block out of initialization and pass in different call_id, it still doesn't work since it seem like the @reply-queue will be locked while waiting for thr1 to finish.
Please let me know if the question is uncleared, thanks in advance for any of your response.
#!/usr/bin/env ruby
# encoding: utf-8
require "bunny"
require "thread"
conn = Bunny.new(:automatically_recover => false)
conn.start
ch = conn.create_channel
class FibonacciClient
attr_reader :reply_queue
attr_accessor :response, :call_id
attr_reader :lock, :condition
def initialize(ch, server_queue)
@ch = ch
@x = ch.default_exchange
@server_queue = server_queue
@reply_queue = ch.queue("", :exclusive => true)
@lock = Mutex.new
@condition = ConditionVariable.new
that = self
@reply_queue.subscribe do |delivery_info, properties, payload|
if properties[:correlation_id] == that.call_id
that.response = payload.to_i
that.lock.synchronize{that.condition.signal}
end
end
end
def call(n)
self.call_id = self.generate_uuid
@x.publish(n.to_s,
:routing_key => @server_queue,
:correlation_id => call_id,
:reply_to => @reply_queue.name)
lock.synchronize{condition.wait(lock)}
response
end
protected
def generate_uuid
# very naive but good enough for code
# examples
"#{rand}#{rand}#{rand}"
end
end
client = FibonacciClient.new(ch, "rpc_queue")
thr1 = Thread.new{
response1 = client.call(30)
puts response1
}
thr2 = Thread.new{
response2 = client.call(40)
puts response2
}
ch.close
conn.close