任务计划程序无法自动刷新过期OAuth令牌问题排查
Dropbox自动上传脚本在任务计划程序中4小时后冻结问题排查与解决
问题详情
- 使用R的rdrop2包实现Dropbox自动上传持续更新的文件,本地RStudio运行完全正常
- 通过Windows任务计划程序执行
Rscript.exe运行脚本时,前4小时正常,之后任务会"冻结"(持续显示"运行"状态但停止上传) - 手动结束并重启任务可恢复正常,但4小时后会重复出现相同问题
- 日志曾提示"Auto-refreshing stale OAuth token",移除
sink日志后问题依旧,推测与OAuth可刷新令牌的刷新逻辑有关 - 已将
Rscript.exe路径添加至系统PATH,任务执行模式为调用Rscript传入脚本
现有脚本
library(rdrop2) library(httr) library(dplyr) setwd("C:/Users/benke/Documents/R Main Directory/Data Upload Automation") error_log <- file("C:/Users/benke/Documents/R Main Directory/Data Upload Automation/error_log.Rout", open = "wt") sink(error_log, type = "message") #Set up refreshable access token, can pass this to any 'drop' function in 'dtoken' argument .dstate <- new.env(parent = emptyenv()) drop_auth_RT <- function (new_user = FALSE, key = "placeholder", secret = "placeholder", cache = TRUE, rdstoken = NA) { if (new_user == FALSE & !is.na(rdstoken)) { if (file.exists(rdstoken)) { .dstate$token <- readRDS(rdstoken) } else { stop("token file not found") } } else { if (new_user && file.exists(".httr-oauth")) { message("Removing old credentials...") file.remove(".httr-oauth") } dropbox <- httr::oauth_endpoint(authorize = "https://www.dropbox.com/oauth2/authorize?token_access_type=offline", access = "https://api.dropbox.com/oauth2/token") # added "?token_access_type=offline" to the "authorize" parameter so that it can return an access token as well as a refresh token dropbox_app <- httr::oauth_app("dropbox", key, secret) dropbox_token <- httr::oauth2.0_token(dropbox, dropbox_app, cache = cache) if (!inherits(dropbox_token, "Token2.0")) { stop("something went wrong, try again") } .dstate$token <- dropbox_token } } refreshable_token <- drop_auth_RT() #Upload updated copy of file drop_upload(file = "biostats.csv", path = "/auto_test", mode = "overwrite", dtoken = refreshable_token)
解决方案建议
1. 为OAuth请求添加超时限制
非交互环境(如任务计划程序)中,无响应的网络请求会导致脚本卡住。在令牌获取/刷新时显式设置超时:
# 修改oauth2.0_token调用,添加30秒超时 dropbox_token <- httr::oauth2.0_token(dropbox, dropbox_app, cache = cache, config = httr::timeout(30)) # 同时给drop_upload也添加超时 drop_upload(file = "biostats.csv", path = "/auto_test", mode = "overwrite", dtoken = refreshable_token, config = httr::timeout(30))
2. 显式管理令牌缓存,避免依赖内部环境
原脚本中使用.dstate内部环境存储令牌,在非交互模式下可能存在上下文丢失问题,改为显式保存/加载令牌文件:
# 修改drop_auth_RT函数,显式保存令牌 drop_auth_RT <- function (new_user = FALSE, key = "placeholder", secret = "placeholder", cache_path = "dropbox_token.rds") { if (!new_user && file.exists(cache_path)) { token <- readRDS(cache_path) # 检查令牌是否即将过期,提前刷新 if (httr::token_expiry(token) < Sys.time() + 300) { token <- httr::oauth2.0_refresh(token) saveRDS(token, cache_path) } return(token) } else { # 原有授权逻辑... dropbox <- httr::oauth_endpoint(authorize = "https://www.dropbox.com/oauth2/authorize?token_access_type=offline", access = "https://api.dropbox.com/oauth2/token") dropbox_app <- httr::oauth_app("dropbox", key, secret) dropbox_token <- httr::oauth2.0_token(dropbox, dropbox_app, cache = FALSE) # 关闭默认缓存,用自定义文件 saveRDS(dropbox_token, cache_path) return(dropbox_token) } } # 调用时加载令牌 refreshable_token <- drop_auth_RT()
3. 改为单次执行+定时触发,避免长会话
不要让脚本持续运行4小时,改为任务计划程序每15-60分钟执行一次单次上传脚本:
- 移除脚本中可能存在的循环逻辑(如果有的话)
- 任务计划程序设置为"按预定计划"执行,时间间隔根据文件更新频率调整
- 每次执行都是全新的R会话,彻底避免令牌刷新时的长连接问题
4. 增强日志调试,定位卡住环节
恢复sink日志,但添加更多调试信息,记录令牌状态和上传步骤:
# 在令牌获取后添加日志 refreshable_token <- drop_auth_RT() cat(paste0("Token loaded, expiry time: ", httr::token_expiry(refreshable_token), "\n"), file = "debug.log", append = TRUE) # 上传前后添加日志 cat(paste0("Starting upload at: ", Sys.time(), "\n"), file = "debug.log", append = TRUE) upload_result <- drop_upload(file = "biostats.csv", path = "/auto_test", mode = "overwrite", dtoken = refreshable_token) cat(paste0("Upload completed at: ", Sys.time(), " Result: ", upload_result$name, "\n"), file = "debug.log", append = TRUE)
5. 更新依赖包到最新版本
旧版本的rdrop2或httr可能存在OAuth刷新的bug,执行以下命令更新:
install.packages(c("rdrop2", "httr"))
内容的提问来源于stack exchange,提问作者bkelley9
相关产品推荐
相关产品推荐

