Skip to content

Commit 19241fb

Browse files
committed
Update embedded async, simplify http tests
Now that async's retry can customize the backoff.
1 parent 2ef0535 commit 19241fb

4 files changed

Lines changed: 25 additions & 14 deletions

File tree

R/aaa-async.R

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2978,9 +2978,13 @@ sseapp <- function() {
29782978
#' - `status_codes`: integer vector of HTTP status codes to retry on.
29792979
#' Defaults to 408, 413, 429, 500, 502, 503, 504, 521, 522 and 524.
29802980
#' - `errors`: whether to retry on connection errors, defaults to `TRUE`.
2981+
#' - `backoff`: a function that takes the (integer) retry attempt number
2982+
#' and returns the number of seconds to wait before the next attempt.
2983+
#' Defaults to an exponential backoff.
29812984
#'
29822985
#' Between retries `async` waits with an exponential backoff, unless the
2983-
#' response has a `Retry-After` header, which is then honored.
2986+
#' response has a `Retry-After` header, which is then honored. Use the
2987+
#' `backoff` entry to customize the wait.
29842988
#' @return Deferred object.
29852989
#'
29862990
#' @section Progress bars:
@@ -3333,7 +3337,7 @@ make_deferred_http <- function(cb, file, method = "GET", retry = TRUE) {
33333337
value$status_code %in% retry$status_codes
33343338
) {
33353339
did <<- did + 1L
3336-
wait <- http_retry_after(value) %||% default_backoff(did)
3340+
wait <- http_retry_after(value) %||% retry$backoff(did)
33373341
delay(wait)$then(function() once())$then(self)
33383342
} else {
33393343
resolve(value)
@@ -3342,7 +3346,7 @@ make_deferred_http <- function(cb, file, method = "GET", retry = TRUE) {
33423346
parent_reject = function(value, resolve) {
33433347
if (retry$errors && did < retry$limit) {
33443348
did <<- did + 1L
3345-
delay(default_backoff(did))$then(function() once())$then(self)
3349+
delay(retry$backoff(did))$then(function() once())$then(self)
33463350
} else {
33473351
stop(value)
33483352
}
@@ -3388,7 +3392,8 @@ http_retry_defaults <- list(
33883392
limit = 2L,
33893393
methods = c("GET", "PUT", "HEAD", "DELETE", "OPTIONS", "TRACE", "QUERY"),
33903394
status_codes = c(408L, 413L, 429L, 500L, 502L, 503L, 504L, 521L, 522L, 524L),
3391-
errors = TRUE
3395+
errors = TRUE,
3396+
backoff = default_backoff
33923397
)
33933398

33943399
get_default_http_retry <- function(retry, method) {

tests/async/test-event-loop.R

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ test_that("repeated delay", {
5959
expect_null(error)
6060
expect_equal(result, 1:10)
6161
expect_true(end - start >= as.difftime(1, units = "secs"))
62-
expect_true(end - start <= as.difftime(2, units = "secs"))
62+
# Loose upper bound: this is only a sanity check that the loop isn't wildly
63+
# slow. A tight bound flakes on busy CI runners.
64+
expect_true(end - start <= as.difftime(5, units = "secs"))
6365
})
6466

6567
test_that("nested event loops", {

tests/async/test-http.R

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,6 @@ test_that("http_retry_after parses the header", {
395395
})
396396

397397
test_that("retryable status codes are retried", {
398-
local_mocked_bindings(default_backoff = function(i) 0)
399398
app <- webfakes::new_app()
400399
app$locals$n <- 0L
401400
app$get("/flaky", function(req, res) {
@@ -410,23 +409,26 @@ test_that("retryable status codes are retried", {
410409
proc <- webfakes::new_app_process(app)
411410
on.exit(proc$stop(), add = TRUE)
412411

413-
# default limit is 2, so the third attempt (a 200) succeeds
414-
resp <- synchronise(http_get(proc$url("/flaky")))
412+
# default limit is 2, so the third attempt (a 200) succeeds.
413+
# `backoff` is set to zero so the test does not sleep between retries.
414+
resp <- synchronise(http_get(
415+
proc$url("/flaky"),
416+
retry = list(backoff = function(i) 0)
417+
))
415418
expect_equal(resp$status_code, 200L)
416419
expect_equal(rawToChar(resp$content), "3")
417420
})
418421

419422
test_that("retries are exhausted and the last response is returned", {
420-
local_mocked_bindings(default_backoff = function(i) 0)
421423
resp <- synchronise(http_get(
422424
http$url("/status/503"),
423-
retry = list(limit = 1)
425+
retry = list(limit = 1, backoff = function(i) 0)
424426
))
425427
expect_equal(resp$status_code, 503L)
426428
})
427429

428430
test_that("retry = FALSE and non-retryable codes do not retry", {
429-
local_mocked_bindings(default_backoff = function(i) 0)
431+
# neither request retries, so no backoff happens
430432
# 404 is not in the default status_codes
431433
resp <- synchronise(http_get(http$url("/status/404")))
432434
expect_equal(resp$status_code, 404L)
@@ -436,9 +438,11 @@ test_that("retry = FALSE and non-retryable codes do not retry", {
436438
})
437439

438440
test_that("connection errors are retried unless disabled", {
439-
local_mocked_bindings(default_backoff = function(i) 0)
440441
err <- tryCatch(
441-
synchronise(http_get("http://127.0.0.1:1/nope", retry = list(limit = 1))),
442+
synchronise(http_get(
443+
"http://127.0.0.1:1/nope",
444+
retry = list(limit = 1, backoff = function(i) 0)
445+
)),
442446
error = identity
443447
)
444448
expect_s3_class(err, "async_rejected")

tests/testthat/test-1-metadata-cache-2.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ test_that("check_update", {
4141
cat("foobar2\n", file = rep_files$rds)
4242
cat("foobar\n", file = pri_files$pkgs$path[1])
4343
cat("foobar2\n", file = pri_files$rds)
44-
data2 <- cmc$check_update()
44+
data2 <- suppressMessages(cmc$check_update())
4545
expect_identical(data, data2)
4646
expect_equal(read_lines(rep_files$pkgs$path[1]), "foobar")
4747

0 commit comments

Comments
 (0)