Очередь вызовов API, чтобы соответствовать пределу скорости

Использование Full Contact API, но они имеют ограничение скорости 300 звонков / минуту. В настоящее время у меня есть его, чтобы установить, что он выполняет вызов API при загрузке файла электронной почты в формате CSV. Я хочу поставить его в очередь так, чтобы, как только он достигнет ограничения скорости или сделал 300 звонков, он ждал 1 минуту и ​​продолжал. Тогда я положу на это delayed_job. Как я могу это сделать? Быстрое решение заключается в использовании

sleep 60 

но как мне найти его таким, чтобы он уже сделал 300 вызовов, сделать его спящим или поставить его в очередь для следующего набора?

def self.import(file)
    CSV.foreach(file.path, headers: true) do |row|
        hashy = row.to_hash
        email = hashy["email"]
        begin
        Contact.create!(email: email, contact_hash: FullContact.person(email: email).to_json) 
        rescue FullContact::NotFound
            Contact.create!(email: email, contact_hash: "Not Found")
        end
    end
end

1 ответ

Здесь есть несколько вопросов, о которых стоит подумать: будет ли один процесс, использующий ваш ключ API, одновременно или возможно, что несколько процессов будут запущены одновременно? Если у вас есть несколько delayed_job рабочие, я думаю, что последнее вероятно. Я не использовал delayed_jobs достаточно, чтобы дать вам хорошее решение, но я чувствую, что вы будете ограничены одним работником.

В настоящее время я работаю над аналогичной проблемой с API с ограничением 1 запрос каждые 0,5 секунды, максимум 1000 в день. Я еще не понял, как я хочу отслеживать ежедневное использование, но я обработал ограничение в секунду, используя потоки. Если вы можете ограничить ограничение как "1 запрос каждые 0,2 секунды", это может освободить вас от необходимости отслеживать его каждую минуту (хотя у вас все еще остается проблема отслеживания нескольких работников).

Основная идея заключается в том, что у меня есть метод запроса, который разбивает один запрос на очередь параметров запроса (на основе максимального количества объектов, разрешенных API-интерфейсом для каждого запроса), а затем другой метод выполняет итерацию по этой очереди и вызывает блок, который отправляет фактический запрос на удаленный сервер. Что-то вроде этого:

def make_multiple_requests(queue, &block)
  result = []
  queue.each do |request|
    timer = Thread.new { sleep REQUEST_INTERVAL }
    execution = Thread.new { result << yield(request) }
    [timer, execution].each(&:join)
  end
  result
end

Чтобы использовать это:

make_multiple_requests(queue) do |request|
  your_request_method_goes_here(request)
end

Основным преимуществом здесь является то, что если запрос занимает больше времени, чем допустимый интервал, вам не нужно ждать, пока sleep чтобы закончить, и вы можете начать свой следующий запрос прямо сейчас. Это просто гарантирует, что следующий запрос не запустится, пока не пройдет хотя бы интервал. Я заметил, что, хотя интервал установлен правильно, я иногда получаю ответ "превышение квоты" от API. В этих случаях запрос повторяется после истечения соответствующего интервала.

Другие вопросы по тегам