Ручное ограничение скорости API

Я пытаюсь написать функцию ограничения скорости вручную для пакета rgithub. Пока это то, что у меня есть:

library(rgithub)

pull <- function(i){
 commits <- get.pull.request.commits(owner = owner, repo = repo, id = i, ctx = get.github.context(), per_page=100)
 links <- digest_header_links(commits)
 number_of_pages <- links[2,]$page
 if (number_of_pages != 0)
   try_default(for (n in 1:number_of_pages){
    if (as.integer(commits$headers$`x-ratelimit-remaining`) < 5)
     Sys.sleep(as.integer(commits$headers$`x-ratelimit-reset`)-as.POSIXct(Sys.time()) %>% as.integer())
  else
    get.pull.request.commits(owner = owner, repo = repo, id = i, ctx = get.github.context(), per_page=100, page = n)
}, default = NULL)
else 
   return(commits)
}

list <- c(500, 501, 502)

pull_lists <- lapply(list, pull)

Намерение состоит в том, что если переменная x-ratelimit-remaining опускается ниже определенного порога, сценарий должен подождать, пока не пройдет время, указанное в x-ratelimit-reset, а затем продолжить сценарий. Тем не менее, я не уверен, что это фактическое поведение if else, которое у меня есть здесь.

Функция работает нормально, но у меня есть некоторые сомнения относительно того, действительно ли она ограничивает скорость или каким-то образом пропускает эти шаги. Поэтому я спрашиваю: а) как я могу узнать, действительно ли он ограничивает скорость, и б) если нет, как я могу переписать его так, чтобы он действительно ограничивал скорость? Будет ли лучше условие/цикл while?


person histelheim    schedule 27.02.2015    source источник
comment
Как и ваша строка }, default = NULL) не соответствует ничему выше. Не могли бы вы исправить это? Следующий else также не имеет соответствующего if выше.   -  person cmbarbu    schedule 21.03.2015
comment
@cmbarbu: должно быть исправлено сейчас.   -  person histelheim    schedule 21.03.2015


Ответы (2)


Вы можете проверить, ограничивает ли он изменение скорости 5 на достаточно большое число и добавляет отображение времени Sys.sleep, используя:

print(system.time(Sys.sleep(...)))

Тем не менее, мне кажется, что с этой функцией все в порядке, но, к сожалению, я не могу ее легко протестировать, поскольку rgithub недоступен для моей версии R (3.1.3).

person cmbarbu    schedule 25.03.2015

Не канонический ответ, а какой-то рабочий пример.
Вы должны добавить логирование в свой скрипт, даже вроде write.csv(append=TRUE).

Я реализовал автоматический процесс антиддос, который предотвращает блокировку вашего IP-адреса на бирже. Вы можете найти его jangorecki/Rbitcoin/R/utils.R.
Rbitcoin.last_api_call — это объект env, хранящийся в пространстве имен пакета, своего рода кэш пакета сеанса.
Это может помочь вам настроить его в вашем пакете.

Вам также следует рассмотреть дополнительную версию с параллельной поддержкой. Связывание с базой данных с параллельным чтением. Моя функция может быть легко изменена для вызова очереди и перепроверки времени каждые X секунд.

Изменить
Я забыл добавить, что упомянутая функция поддерживает несколько исходных систем. Это позволяет, например, расширить ваш rgithub для битбакета и т. д. и по-прежнему эффективно управлять ограничением скорости API.

person jangorecki    schedule 21.03.2015
comment
Не могли бы вы привести пример того, как добавить логирование в скрипт? - person histelheim; 22.03.2015
comment
@histelheim проверьте futile.logger в CRAN. Это действительно классный и полезный пакет. - person daroczig; 23.03.2015
comment
@histelheim futile.logger предназначен для более расширенного ведения журнала, если вы хотите просто посмотреть, работает ли ваш процесс, вы можете использовать все, что будет печатать состояние. От печати в консоль message(paste("time spent waiting:",x)) до печати в файл write.csv(..., append=TRUE) или множество других вариантов. В моем связанном примере я использовал опцию verbose и функцию cat для печати секунд, потраченных на ожидание консоли. - person jangorecki; 24.03.2015