-
Notifications
You must be signed in to change notification settings - Fork 82
Closed
Description
Reprex:
library(httr2)
# Setup the query
url <- "https://whatever.com"
req <- request(url) |>
req_throttle(capacity = 5, fill_time_s = 5)
Sys.sleep(2)
# Simulate fast use of req_throttle tokens
for (n in 1:15) {
print(httr2:::the$throttle[[req$policies$throttle_realm]]$take_token())
}
#> [1] 0
#> [1] 0
#> [1] 0
#> [1] 0
#> [1] 0
#> [1] -1
#> [1] 0
#> [1] 1
#> [1] 2
#> [1] 3
#> [1] 4
#> [1] 5
#> [1] 6
#> [1] 7
#> [1] 8Created on 2025-12-05 with reprex v2.1.1
Why this is an issue
This is an issue because the internal httr2:::sys_sleep() function used internally by req_perform() does not handle that edge case gracefully:
...
sys_sleep(throttle_delay(req), "for throttling delay")
...(see: L104)
...as it only checks explicitly for time == 0 and therefore just goes ahead and feeds negative values into Sys.sleep() – as shown below:
httr2:::sys_sleep
#> function (seconds, task, fps = 10, progress = NULL)
#> {
#> check_number_decimal(seconds)
#> check_string(task)
#> check_number_decimal(fps)
#> progress <- progress %||% getOption("httr2_progress", !is_testing())
#> check_bool(progress, allow_null = TRUE)
#> if (seconds == 0) {
#> return(invisible())
#> }
#> if (!progress) {
#> cli::cli_alert("Waiting {round(seconds, 2)}s {task}")
#> Sys.sleep(seconds)
#> return(invisible())
#> }
#> start <- cur_time()
#> signal("", class = "httr2_sleep", seconds = seconds)
#> cli::cli_progress_bar(format = "Waiting {ceiling(seconds)}s {task} {cli::pb_bar}",
#> total = seconds * fps)
#> while ({
#> left <- start + seconds - cur_time()
#> left > 0
#> }) {
#> Sys.sleep(min(1/fps, left))
#> cli::cli_progress_update(set = (seconds - left) * fps)
#> }
#> cli::cli_progress_done()
#> invisible()
#> }
#> <bytecode: 0x110a958a0>
#> <environment: namespace:httr2>Created on 2025-12-05 with reprex v2.1.1
How I found the issue
My self-hosted github runner regularly throws this error:
Workarounds
I haven't found any yet.
(Except to stop using req_throttle, of course.)
Metadata
Metadata
Assignees
Labels
No labels