简体   繁体   中英

How to implement RPC with RabbitMQ in Rails?

I want to implement an action that calls remote service with RabbitMQ and presents returned data. I implemented this (more as a proof of concept so far) in similar way to example taken from here: https://github.com/baowen/RailsRabbit and it looks like this:

controller:

def rpc
  text = params[:text]
  c = RpcClient.new('RPC server route key')
  response = c.call text
  render text: response
end

RabbitMQ RPC client:

class RpcClient < MQ
  attr_reader :reply_queue
  attr_accessor :response, :call_id
  attr_reader :lock, :condition

  def initialize()
    # initialize exchange:

    conn = Bunny.new(:automatically_recover => false)
    conn.start
    ch = conn.create_channel

    @x = ch.default_exchange
    @reply_queue = ch.queue("", :exclusive => true)
    @server_queue = 'rpc_queue'

    @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_s
        that.lock.synchronize { that.condition.signal }
      end
    end
  end

  def call(message)
    self.call_id = generate_uuid
    @x.publish(message.to_s,
               routing_key: @server_queue,
               correlation_id: call_id,
               reply_to: @reply_queue.name)

    lock.synchronize { condition.wait(lock) }
    response
  end

  private

  def generate_uuid
    # very naive but good enough for code
    # examples
    "#{rand}#{rand}#{rand}"
  end
end

A few tests indicate that this approach works. On the other hand, this approach assumes creating a client (and subscribing to the queue) for every request on this action, which is inefficient according to the RabbitMQ tutorial . So I've got two questions:

  1. Is it possible to avoid creating a queue for every Rails request?
  2. How will this approach (with threads and mutex) interfere with my whole Rails environment? Is it safe to implement things this way in Rails? I'm using Puma as my web server, if it's relevant.

Is it possible to avoid creating a queue for every Rails request?

Yes - there is no need for every single request to have it's own reply queue.

You can use the built-in direct-reply queue. See the documentation here .

If you don't want to use the direct-reply feature, you can create a single reply queue per rails instance. You can use a single reply queue, and have the correlation id help you figure out where the reply needs to go within that rails instance.

How will this approach (with threads and mutex) interfere with my whole Rails environment? Is it safe to implement things this way in Rails?

what's the purpose of the lock / mutex in this code? doesn't seem necessary to me, but i'm probably missing something since i haven't done ruby in about 5 years :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM