webshot::webshot()遗留未关闭文件连接的原因及自动关闭方法
问题:webshot::webshot()遗留FIFO连接导致R CMD check报错
在R包函数中使用webshot::webshot(),且在roxygen2头文件中提供可运行示例时,执行R CMD check会触发如下错误:
Error: connections left open:
/tmp/... (fifo)
/tmp/... (fifo)
Execution halted
该问题可在包环境外复现,步骤如下:
# 查看初始连接 showConnections(all = TRUE)
输出:
description class mode text isopen can read can write 0 "stdin" "terminal" "r" "text" "opened" "yes" "no" 1 "stdout" "terminal" "w" "text" "opened" "no" "yes" 2 "stderr" "terminal" "w" "text" "opened" "no" "yes"
# 执行webshot(部分OS需设置OPENSSL_CONF) Sys.setenv(OPENSSL_CONF = "/dev/null") # 依OS决定是否需要 webshot::webshot("https://github.com/rstudio/shiny") # 使用webshot 0.5.5版本 Sys.unsetenv(OPENSSL_CONF) # 依OS决定是否需要 # 再次查看连接 showConnections(all = TRUE)
输出:
description class mode text isopen can read can write 0 "stdin" "terminal" "r" "text" "opened" "yes" "no" 1 "stdout" "terminal" "w" "text" "opened" "no" "yes" 2 "stderr" "terminal" "w" "text" "opened" "no" "yes" 3 "/tmp/..." "fifo" "w+" "text" "opened" "yes" "yes" 4 "/tmp/..." "fifo" "w+" "text" "opened" "yes" "yes"
原因分析
webshot 0.5.5依赖PhantomJS作为截图引擎,PhantomJS启动时会创建FIFO管道(命名管道),用于和R进程双向通信,传递截图指令与结果。在交互式环境中,这些连接可能会被自动回收,但在非交互式环境(如R CMD check运行示例)中,PhantomJS进程退出后,R端未自动触发FIFO连接的关闭逻辑,导致连接残留。
解决方法
1. 手动关闭遗留FIFO连接
调用webshot()后,筛选出所有处于打开状态的FIFO连接并关闭:
# 定义清理函数 close_fifo_conns <- function() { # 获取所有连接信息 conn_list <- showConnections(all = TRUE) # 筛选出打开的FIFO连接下标 fifo_indices <- which(conn_list$class == "fifo" & conn_list$isopen) # 逐个关闭连接 if (length(fifo_indices) > 0) { invisible(lapply(fifo_indices, function(i) close(getConnection(i)))) } } # 使用示例 Sys.setenv(OPENSSL_CONF = "/dev/null") webshot::webshot("https://github.com/rstudio/shiny") Sys.unsetenv(OPENSSL_CONF) close_fifo_conns()
2. 在包函数中自动执行关闭逻辑
借助withr::defer(),确保无论函数是否正常执行,都会在退出时关闭连接,适合包内函数使用:
my_screenshot <- function(url, ...) { # 注册退出时自动执行的清理逻辑 withr::defer(close_fifo_conns()) # 执行截图操作 Sys.setenv(OPENSSL_CONF = "/dev/null") # 按需添加 result <- webshot::webshot(url, ...) Sys.unsetenv(OPENSSL_CONF) # 按需添加 return(result) } # 配套的清理函数 close_fifo_conns <- function() { conn_list <- showConnections(all = TRUE) fifo_indices <- which(conn_list$class == "fifo" & conn_list$isopen) if (length(fifo_indices) > 0) { invisible(lapply(fifo_indices, function(i) close(getConnection(i)))) } }
3. 迁移至webshot2(推荐)
webshot2是webshot的官方替代版本,使用Chrome/Chromium而非PhantomJS作为引擎,从根本上避免了FIFO连接遗留问题,同时支持更多现代网页特性。只需替换包依赖与函数调用:
# 安装webshot2 install.packages("webshot2") # 替换原有调用 webshot2::webshot("https://github.com/rstudio/shiny")
内容的提问来源于stack exchange,提问作者Patrick
相关产品推荐
相关产品推荐

