限制异步流程执行

时间:2013-06-14 16:56:28

标签: ruby recursion hydra

我有一个使用hydra来请求页面的程序。我想限制下载队列中的项目数。 hydra.queue调用是非阻塞的,因此我需要以某种方式在旧的完成处理时触发新的下载。当前的解决方案使用递归。

def perform
  @hydra = Typhoeus::Hydra.new(:max_concurrency => 100)
  @target_concurrency.times {process_next_product}
end

def process_next_product
  if id = $redis.lpop(REDIS_UNSCRAPED_PRODUCTS_KEY)
    product = Product.find(id).url
    req = Typhoeus::Request.new(product.url, {:follow_location => true})

    req.on_complete do |resp|
      process_product_response(product, resp.body)
    end
    @hydra.queue(req)
  end
end

def process_product_response(product, response)
  # process product
  process_next_product
end

随着调用堆栈的增长,此解决方案正在占用内存。我想要一个解决方案,允许我在不使用递归的情况下将 x 项保留在hydra队列中。

2 个答案:

答案 0 :(得分:0)

我采用的解决方案是使用信号触发处理下一个条目:

def perform
  @hydra = Typhoeus::Hydra.new(:max_concurrency => 100)
  set_trap
  @target_concurrency.times { Process.kill("USR1", Process.pid) }
end

def set_trap
  Signal.trap('USR1') do
    if id = $redis.lpop(REDIS_UNSCRAPED_PRODUCTS_KEY)
      product = Product.find(id).url
      req = Typhoeus::Request.new(product.url, {:follow_location => true})

      req.on_complete do |resp|
        process_product_response(product, resp.body)
      end
      @hydra.queue(req)
    end
  end
end

def process_product_response(product, response)
  # process product
  Process.kill("USR1", Process.pid)
end

答案 1 :(得分:0)

我不确定你需要什么。您可以使用max_concurrency选项设置并行请求的上限。