如果错误,我怎么能简单地告诉R重试一次语句?例如。我希望能做到这样的事情:
tryCatch(dbGetQuery(...), # Query database
error = function(e) {
if (is.locking.error(e)) # If database is momentarily locked
retry(times = 3) # retry dbGetQuery(...) 3 more times
else {
# Handle other errors
}
}
)
答案 0 :(得分:35)
我通常将try
块放在循环中,
并在循环不再失败或达到最大尝试次数时退出循环。
some_function_that_may_fail <- function() {
if( runif(1) < .5 ) stop()
return(1)
}
r <- NULL
attempt <- 1
while( is.null(r) && attempt <= 3 ) {
attempt <- attempt + 1
try(
r <- some_function_that_may_fail()
)
}
答案 1 :(得分:8)
我编写了一个快速功能,允许您轻松地重试操作可配置的次数,并在尝试之间进行可配置的等待:
library(futile.logger)
library(utils)
retry <- function(expr, isError=function(x) "try-error" %in% class(x), maxErrors=5, sleep=0) {
attempts = 0
retval = try(eval(expr))
while (isError(retval)) {
attempts = attempts + 1
if (attempts >= maxErrors) {
msg = sprintf("retry: too many retries [[%s]]", capture.output(str(retval)))
flog.fatal(msg)
stop(msg)
} else {
msg = sprintf("retry: error in attempt %i/%i [[%s]]", attempts, maxErrors,
capture.output(str(retval)))
flog.error(msg)
warning(msg)
}
if (sleep > 0) Sys.sleep(sleep)
retval = try(eval(expr))
}
return(retval)
}
所以你可以写val = retry(func_that_might_fail(param1, param2), maxErrors=10, sleep=2)
来重试用这些参数调用那个函数,在10次错误后放弃,并在两次尝试之间休息2秒。
此外,您可以通过将不同的函数作为参数isError
传递来重新定义错误的含义,默认情况下会捕获用stop
发出的错误。如果被调用的函数在出错时执行其他操作,例如返回FALSE
或NULL
,这将非常有用。
这是我迄今为止发现的替代方案,可以产生更清晰,更易读的代码。
希望这有帮助。
答案 2 :(得分:7)
没有预先指定值并使用for
代替while
的解决方案:
some_function_that_may_fail <- function(i) {
if( runif(1) < .5 ) stop()
return(i)
}
for(i in 1:10){
try({
r <- some_function_that_may_fail(i)
break #break/exit the for-loop
}, silent = FALSE)
}
r
将等于所需的尝试次数。如果您不希望将错误集silent
设置为TRUE
答案 3 :(得分:5)
这是一个生成自定义条件以响应
的函数locked <- function(message="occurred", ...) {
cond <- simpleCondition(message, ...)
class(cond) <- c("locked", class(cond))
cond
}
和一个允许(无限次)重启的函数
f <- function() {
cnt <- 0L
repeat {
again <- FALSE
cnt <- cnt + 1L
withRestarts({
## do work here, and if needed...
signalCondition(locked())
}, retry=function() {
again <<- TRUE
})
if (!again) break
}
cnt
}
并使用withCallingHandlers
(以保持条件被发信号的上下文不同于tryCatch
)来处理locked
条件
withCallingHandlers({
n_tries <- 0L
f()
}, locked=function(e) {
n_tries <<- n_tries + 1L
if (n_retries < 3)
invokeRestart("retry")
})
答案 4 :(得分:0)
我喜欢从一开始就将对象设置为错误,如果您遇到连接问题,有时还可以增加一些睡眠时间:
res <- simpleError("Fake error to start")
counter <- 1
max_tries <- 10
while(inherits(res, "error") | counter < max_tries) {
# Sys.sleep(2*counter)
res <- tryCatch({ your_fun(...) },
error = function(e) e)
counter <- counter + 1
}
答案 5 :(得分:0)
我整理了代码并将其打包:retry
f <- function(x) {
if (runif(1) < 0.9) {
stop("random error")
}
x + 1
}
# keep retring when there is a random error
retry::retry(f(1), when = "random error")
#> [1] 2
# keep retring until a requirement is satisified.
retry::retry(f(1), until = function(val, cnd) val == 2)
#> [1] 2
# or using one sided formula
retry::retry(f(1), until = ~ . == 2, max_tries = 10)
#> [1] 2