Подтвердить что ты не робот

Как повторить выражение об ошибке?

Как я могу просто сказать 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
        }
    }
)
4b9b3361

Ответ 1

Я обычно помещаю блок 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()
  )
} 

Ответ 2

Я написал быструю функцию, которая позволяет вам легко повторять операцию с настраиваемым количеством раз, с настраиваемым ожиданием между попытками:

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.

Это альтернатива, которую я нашел до сих пор, что приводит к более четкому и понятному коду.

Надеюсь, что это поможет.

Ответ 3

Решение без предварительно назначаемых значений и используя 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

Ответ 4

Здесь функция для создания пользовательского условия для ответа на

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")
})

Ответ 5

Мне нравится устанавливать свой объект как ошибку с самого начала, также иногда полезно добавить время сна, если у вас проблемы с подключением:

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
}