Настройка:
У меня есть скрипт R на удаленном сервере, который должен подключаться к внешней базе данных, извлекать некоторые данные, запускать некоторые модели и сохранять результаты. Поскольку эта операция занимает много времени, я использую crontab, чтобы запланировать ее выполнение в ночное время (я пробовал разные начальные часы).
Чтобы подключиться к базе данных, я использую RJDB C (вы можете Предлагаю другой пакет, но мне бы очень хотелось не менять его :)). Двумя ключевыми функциями в рамках этого вопроса являются dbConnect (для создания соединения с внешней базой данных) и dbSendQuery (для отправки запросов).
Первоначальная проблема
Я понял, что по нескольким причинам иногда запросы, которые я отправляю в базу данных, отключаются на стороне базы данных (возможно, из-за некоторых проблем с обслуживанием). Не забывайте, что указанные запросы «правильные» - если я попытаюсь запустить их позже, они будут работать. Поскольку я не могу изменить поведение на стороне базы данных, я попытался реализовать некоторую устойчивость этого поведения в своем коде.
Первоначальное решение
Я написал ряд функций-оболочек для dBConnect и dBSendQuery, который должен в случае ошибки подождать некоторое время, а затем повторить попытку
jdbcDriver = JDBC(driverClass="oracle.jdbc.OracleDriver",
classPath=here::here("OJDBC-Full/ojdbc6.jar"))
credentials = list()
credentials$user = 'user'
credentials$pass = 'password'
credentials$driver = jdbcDriver
credentials$host ="jdbc:oracle:thin:@//host"
#I changed the user, pass, and host for privacy issues
dbConnectSafe = function(credentials) {
connection = try(dbConnect(credentials$driver,
credentials$host,
credentials$user,
credentials$pass),
silent = T)
timeout = 60
while (class(connection) == "try-error") {
print(paste("Problem with connection. Wait", timeout, "seconds and retry."))
try(dbDisconnect(connection), silent = T)
Sys.sleep(timeout)
connection = try(dbConnect(credentials$driver,
credentials$host,
credentials$user,
credentials$pass),
silent = T)
Sys.sleep(1)
timeout = timeout + 60
}
return(connection)
}
dbSendQuerySafe = function(connection, query, credentials) {
result = try(dbSendQuery(connection, query), silent = T)
timeout = 60
while (class(result) == "try-error") {
print(paste("Poblem sending query. Waiting",timeout,
"seconds, then restart connection and retry."))
Sys.sleep(timeout)
try(dbDisconnect(connection), silent = T)
connection <- dbConnectSafe(credentials)
result = try(dbSendQuery(connection, query), silent = T)
Sys.sleep(1)
timeout = timeout + 60
}
return(result)
}
Помните, что фактические вызовы dbSendQuery находятся внутри функций, которые сами также находятся в try Catch. Что-то вроде:
someFunction = function(credentials){
query = "select * from table"
connection = dbConnectSafe(credentials)
temp = dbSendQuerySafe(connection, query, credentials)
data = data.table()
go = T
while(go){
chunk = dbFetch(temp, 10000)
if(nrow(chunk) > 0){
data = rbind(data, data.table(chunk))
}else{
go = F
}
}
dbClear(temp)
return(data)
}
done = tryCatch(someFunction( credentials),
error = function(err) {
print("Error")
return(F)
})
Актуальная проблема
Все это, чтобы прибыть сюда. Я понимаю, что иногда, в некоторой непредсказуемой форме, мой Rscript действительно падает. Учитывая приведенный выше пример кода, я ожидал, что после того, как мой запрос будет уничтожен на стороне БД, мой код будет обрабатывать его, ждать и повторять, не прерывая работу.
Однако я получаю следующее:
*** caught segfault ***
address (nil), cause 'unknown'
Traceback:
1: .External(interface, as.character(obj), returnSig, method, ...)
2: .jcall("java/sql/DriverManager", "Ljava/sql/Connection;", "getConnection", as.character(url)[1], as.character(user)[1], as.character(password)[1], check = FALSE)
3: .local(drv, ...)
4: dbConnect(credentials$driver, credentials$host, credentials$user, credentials$pass)
5: dbConnect(credentials$driver, credentials$host, credentials$user, credentials$pass)
6: doTryCatch(return(expr), name, parentenv, handler)
7: tryCatchOne(expr, names, parentenv, handlers[[1L]])
8: tryCatchList(expr, classes, parentenv, handlers)
9: tryCatch(expr, error = function(e) { call <- conditionCall(e) if (!is.null(call)) { if (identical(call[[1L]], quote(doTryCatch))) call <- sys.call(-4L) dcall <- deparse(call)[1L] prefix <- paste("Error in", dcall, ": ") LONG <- 75L msg <- conditionMessage(e) sm <- strsplit(msg, "\n")[[1L]] w <- 14L + nchar(dcall, type = "w") + nchar(sm[1L], type = "w") if (is.na(w)) w <- 14L + nchar(dcall, type = "b") + nchar(sm[1L], type = "b") if (w > LONG) prefix <- paste0(prefix, "\n ") } else prefix <- "Error : " msg <- paste0(prefix, conditionMessage(e), "\n") .Internal(seterrmessage(msg[1L])) if (!silent && identical(getOption("show.error.messages"), TRUE)) { cat(msg, file = stderr()) .Internal(printDeferredWarnings()) } invisible(structure(msg, class = "try-error", condition = e))})
10: try(dbConnect(credentials$driver, credentials$host, credentials$user, credentials$pass), silent = T)
11: dbConnectSafe(credentials)
12: dbSendQuerySafe(connection, query, credentials)
13: doTryCatch(return(expr), name, parentenv, handler)
14: tryCatchOne(expr, names, parentenv, handlers[[1L]])
15: tryCatchList(expr, classes, parentenv, handlers)
16: tryCatch(someFunction(credentials = credentials), error = function(err) { print("Error") return(F) })
An irrecoverable exception occurred. R is aborting now ...
Почему R вылетает при использовании try-catch
? Как я могу решить это?