繁体   English   中英

如何在出错时重试语句?

[英]How to retry a statement on error?

如果语句出错,我如何简单地告诉 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
        }
    }
)

我通常将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()
  )
} 

我编写了一个快速函数,允许您轻松地重试可配置的操作次数,并在尝试之间设置可配置的等待时间:

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发出的错误信号。 如果被调用的函数在错误时执行其他操作,例如返回FALSENULL ,这将很有用。

这是我迄今为止发现的替代方法,可以生成更清晰、更易读的代码。

希望这可以帮助。

没有预先分配值并使用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将等于所需的尝试次数。 如果你不想在错误的输出设定silentTRUE

这是一个生成自定义条件以响应的函数

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不同,保持条件被激活的tryCatch )来处理locked条件

withCallingHandlers({
    n_tries <- 0L
    f()
}, locked=function(e) {
    n_tries <<- n_tries + 1L
    if (n_retries < 3)
        invokeRestart("retry")
})

我喜欢从一开始就将我的对象设置为错误,如果您遇到连接问题,有时也可以添加一些睡眠时间:

res <- simpleError("Fake error to start")
counter <- 1
max_tries <- 10 
# Sys.sleep(2*counter)
while(inherits(res, "error") & counter < max_tries) { 
  res <- tryCatch({ your_fun(...) }, 
      error = function(e) e)
  counter <- counter + 1
}

我已经把代码放在一起并打包:重试

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM