我试着把所有的东西都读了,但是我被一个问题困住了。通过使用bigrquery,我创建了对Google BigQuery的查询来获取数据--不幸的是,有时我的查询由于超时而无法工作。Q是一个SQL-查询,BQ用来存储从BigQuery下载的数据。
有人知道如何在每次tryCatch给我错误时重做循环吗?
到目前为止我已经知道了:
BQ_Foo <- NULL
tryCatch(
{
repeat{
BQ_Foo <- query_exec(Q_foo,"bigquery")
if(is.list(BQ_Foo) == TRUE)break }
}
,error=function(e){cat("ERROR : Query not loaded!", "\n")}
)
编辑:
我再次尝试了我的第一种方法,这一次我收到了以下错误消息:
Curl::curl_fetch_memory中的错误(url,句柄=句柄): 操作被应用程序回调中止。
有人知道怎么处理这件事吗?
发布于 2016-07-29 04:16:09
广泛地基于r2evans的答案,下面是如何用withRestarts
做同样的事情,并得到这篇博客文章的一些帮助
set.seed(2)
foo <- NULL
operation <- function(x,tries) {
message(paste("x is",x,"remaining tries",tries))
withRestarts(
tryCatch({
if (runif(1) < x) stop("fail!") else 1
},
error=function(e) { invokeRestart("retry")}),
retry = function() {
message("Retrying")
stopifnot(tries > 0)
operation(x,tries-1)
}
)
}
> operation(0.9,5)
# x is 0.9 remaining tries 5
# Retrying
# x is 0.9 remaining tries 4
# Retrying
# x is 0.9 remaining tries 3
# Retrying
# x is 0.9 remaining tries 2
# Retrying
# x is 0.9 remaining tries 1
[1] 1
这是一种递归调用,所以在再次调用函数之前,您可以做任何您想做的事情。
您可以用同样的方式在tryCatch错误处理程序中这样做,使用重新启动处理程序的兴趣是调用特定的函数,如果您有两个tryCatch,您想要的处理程序行为几乎相同,那么您可以添加一个参数,并在每次尝试捕获时使用相同的处理程序,即:
testfun <- function(x) {
withRestarts({
tryCatch(
{
ifelse(runif(1) < 0.5,stop("Error Message"),warning("Warning message"))
},
warning=function(e) { invokeRestart("logger", level="warning", message=e ) },
error=function(e) { invokeRestart("logger", level="error", message=e ) }
)
},
logger = function(level,message) {
message(date()," [",level,"]: ",message[['message']])
}
)
}
给予:
> set.seed(2)
> testfun()
Fri Jul 29 14:15:11 2016 [error]: Error Message
> testfun()
Fri Jul 29 14:15:12 2016 [warning]: Warning message
> testfun()
Fri Jul 29 14:15:13 2016 [warning]: Warning message
> testfun()
Fri Jul 29 14:15:13 2016 [error]: Error Message
这里主要关注的是记录器方法的分解和减少代码重复。
发布于 2016-07-28 08:13:55
天真解决方案
首先,您可能会稍微天真地尝试将重复/在tryCatch
之外放置,如下所示:
set.seed(2)
foo <- NULL
while (is.null(foo)) {
foo <- tryCatch({
if (runif(1) < 0.9) stop("fail!") else 1
},
error = function(e) { message("err"); NULL; }
)
}
# err
# err
# err
# err
message("success: ", foo)
# success: 1
不幸的是,您引入了循环永远不会返回的可能性。为了防止这种情况,你可以试试柜台.
较少的钠溶液
set.seed(2)
foo <- NULL
max_attempts <- 3
counter <- 0
while (is.null(foo) && counter < max_attempts) {
counter <- counter + 1
foo <- tryCatch({
if (runif(1) < 0.9) stop("fail!") else 1
},
error = function(e) { message("err"); NULL; }
)
}
# err
# err
# err
if (is.null(foo)) message("final failure") else message("success: ", foo)
# final failure
现在,这对您更好,但它仍然可能无意中引入拒绝服务“攻击”在服务器上。(请考虑“为什么”查询失败:如果是因为服务器暂时被淹没,那么即使是对一些有限的请求,也会使情况变得更糟。)虽然它会稍微减慢您的速度,但是对于繁忙的服务器来说,暂停会减轻服务器的负担,并且可能给您更好的机会在失败之前获得成功的查询。
更好的解决方案
在网络术语中,小的TCP数据包在重复尝试时会导致拥塞(请参阅纳格尔算法以获得快速参考)。使用某种形式的指数退避是很常见的,为了防止两个(或更多)客户机同时做完全相同的退避,一些客户机稍微抖动(例如,httr::RETRY
)。
set.seed(2)
foo <- NULL
max_attempts <- 3
# borrowed from hadley/httr::RETRY
pause_cap <- pause_base <- 1
counter <- 0
while (is.null(foo) && counter < max_attempts) {
if (counter > 0L) {
length <- stats::runif(1, max = min(pause_cap, pause_base * (2 ^ counter)))
message("sleeping ", round(length, 1))
Sys.sleep(length)
}
counter <- counter + 1
foo <- tryCatch({
if (runif(1) < 0.9) stop("fail!") else 1
},
error = function(e) { message("err"); NULL; }
)
}
# err
# sleeping 0.7
# err
# sleeping 0.2
if (is.null(foo)) message("final failure") else message("success: ", foo)
# success: 1
结业
有些草率的代码,但我希望你明白重点。在没有某种自我限制的情况下在网络查询上设置循环,很容易升级为无意中的DOS。
发布于 2016-07-29 04:46:18
基于您的想法,我创建了这段代码,这似乎是可行的-我只需要强调它。
QFoo <- paste0('SQL Code', dateBQ, ' ')
BQFoo <- NULL
testfun <- function(QFoo) {
withRestarts({
tryCatch({
query_exec(QFoo, "bigquery")
},
warning = function(e) { invokeRestart("logger", level="warning", message = e) },
error = function(e) { invokeRestart("logger", level="error", message = e) })
},
logger = function(level, message) {
message(date(), " [", level, "]: ", message[['message']])
})
}
testfun(QFoo)
https://stackoverflow.com/questions/38641083
复制相似问题