具有限制的api并发访问

时间:2014-05-14 04:55:12

标签: ruby design-patterns concurrency sidekiq

这个问题不仅仅是关于红宝石的。

我有很多工作正在运行以创建许多与外部API的连接。此API有一个限制 现在我使用sidekiq和redis来限制访问 即在每次访问API时,我都会运行工作人员 然后工作人员启动它检查上次访问API的时间,如果早于该API允许,则重新安排工作人员,否则在redis中触摸时间并运行请求。

例如:

def run_or_schedule
  limiter = RedisLimiter.new(account_token)
  if limiter.can_i_run?
    limiter.like
    run
  else
    ApiWorker.perform_at(limiter.next_like, *params)
  end
end

问题是我创建了很多请求,并且他们多次重新安排。

也许有人可以推荐更好的解决方案吗?

也许存在任何设计模式?

2 个答案:

答案 0 :(得分:1)

您使用的轮询方法的一种替代方法是拥有supervisor

因此,不是让每个工作人员自己处理问题,而是让另一个对象/工人/进程决定下一个工作人员何时运行。

如果API在请求之间设置了时间限制,您可以让此主管在时间限制允许的情况下执行。

如果限制更复杂(例如,每X间隔的请求总数),您可以让主管持续运行并且在达到该间隔量的限制块(休眠)时运行。恢复后,它可以从队列中继续下一个工作人员。

这种方法的一个明显优势是,您可以跳过与实例化的每个单独工作人员相关的开销,检查自己是否应该运行,并且如果不应该重新安排。

答案 1 :(得分:1)

您可以使用一个队列,以及一个以允许的最大速率发送事件(等待时)的专用线程。

假设您可以每秒发送一个API调用,您可以执行以下操作:

class APIProxy
  def like(data)
    @like_queue << data
  end

  def run
    Thread.new do
      @like_queue = Queue.new
      loop do
        actual_send_like @like_queue.pop
        sleep 1
      end
    end
  end

  private
  def actual_send_like(data)
    # use the API you need
  end
end