【问题标题】:How to implement RPC with RabbitMQ in Rails?如何在 Rails 中使用 RabbitMQ 实现 RPC?
【发布时间】:2016-01-21 14:27:46
【问题描述】:

我想实现一个使用 RabbitMQ 调用远程服务并呈现返回数据的操作。我以与从此处获取的示例类似的方式实现了这个(到目前为止更多是作为概念证明):https://github.com/baowen/RailsRabbit,它看起来像这样:

控制器:

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

RabbitMQ RPC 客户端:

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

一些测试表明这种方法有效。另一方面,这种方法假定为该操作的每个请求创建一个客户端(并订阅队列),根据RabbitMQ tutorial,这是低效的。所以我有两个问题:

  1. 是否可以避免为每个 Rails 请求创建队列?
  2. 这种方法(使用线程和互斥锁)将如何干扰我的整个 Rails 环境?在 Rails 中以这种方式实现是否安全?我使用 Puma 作为我的网络服务器,如果它是相关的。

【问题讨论】:

标签: ruby-on-rails ruby multithreading rabbitmq rpc


【解决方案1】:

是否可以避免为每个 Rails 请求创建队列?

是的 - 不需要每个请求都有自己的回复队列。

您可以使用内置的直接回复队列。见the documentation here

如果您不想使用直接回复功能,您可以为每个 rails 实例创建一个回复队列。您可以使用单个回复队列,并让相关 ID 帮助您确定回复需要在该 rails 实例中的位置。

这种方法(使用线程和互斥锁)将如何干扰我的整个 Rails 环境?在 Rails 中以这种方式实现是否安全?

这段代码中锁/互斥的目的是什么?对我来说似乎没有必要,但我可能错过了一些东西,因为我大约 5 年没有做过 ruby​​ 了:)

【讨论】:

  • 感谢您的回答 - 我会尝试直接回复队列。关于RabbitMQ,我可能还有其他问题要问你,因为我觉得我对这个的理解还不够。
  • 好的,这是我的第一个问题。在我将消息发布到 RPC 并得到返回的答案后,我尝试发布另一条消息,但它抛出了 PRECONDITION_FAILED - reply consumer already set 错误。每个应用程序是否必须为此 'amq.rabbitmq.reply-to 队列创建一个使用者?
猜你喜欢
  • 2011-04-09
  • 2019-08-15
  • 2015-04-15
  • 2023-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-16
  • 2017-07-05
相关资源
最近更新 更多