构建轮询外部服务(RoR)的最佳方式

时间:2013-07-25 22:24:41

标签: ruby-on-rails ruby polling

我有一个Rails应用程序,其Document标志为available。该文档被上传到外部服务器,在那里它不能立即可用(需要时间来传播)。我想做的是轮询可用性并在可用时更新模型。

我正在为此流程寻找性能最佳的解决方案(服务不提供回调):

  1. Document已上传到应用
  2. app上传到外部服务器
  3. app轮询网址(http://external.server.com/document.pdf)直到可用
  4. 应用更新型号Document.available = true
  5. 我被困在3.我已经在我的项目中使用了sidekiq。这是一种选择,还是应该使用完全不同的方法(cron作业)。

    Documents将一直上传,因此首先轮询数据库/ redis以检查不可用的Documents似乎相关。

1 个答案:

答案 0 :(得分:0)

请参阅此答案:Making HTTP HEAD request with timeout in Ruby

基本上你为已知的url设置一个HEAD请求,然后异步循环,直到你得到一个200(在迭代之间有5秒的延迟,或者其他)。

上传文档后,从控制器执行此操作:

Document.delay.poll_for_finished(@document.id)

然后在您的文档模型中:

def self.poll_for_finished(document_id)
  document = Document.find(document_id)
  # make sure the document exists and should be polled for
  return unless document.continue_polling?

  if document.remote_document_exists?
    document.available = true
  else
    document.poll_attempts += 1 # assumes you care how many times you've checked, could be ignored.
    Document.delay_for(5.seconds).poll_for_finished(document.id)
  end
  document.save
end

def continue_polling?
  # this can be more or less sophisticated
  return !document.available || document.poll_attempts < 5
end

def remote_document_exists?
  Net::HTTP.start('http://external.server.com') do |http|
    http.open_timeout = 2
    http.read_timeout = 2
    return "200" == http.head(document.path).code
  end
end

这仍然是阻止操作。如果您尝试联系的服务器运行缓慢或无响应,则打开Net :: HTTP连接将阻止。如果你担心它使用Typhoeus。有关详细信息,请参阅此答案:What is the preferred way of performing non blocking I/O in Ruby?