如何在R Shiny中实现清理程序?

mch*_*hen 17 r shiny

例如,我闪亮的应用程序可能会打开数据库连接

# server.R
db <- dbConnect("SQLite", DB_PATH)
shinyServer(
    ...  # things involving db
)
Run Code Online (Sandbox Code Playgroud)

现在,当Shiny会话结束时,如何确保连接db正确关闭(通过dbDisconnect(db))?实际上,应该为连接到服务器的每个客户端执行清理,还是仅执行一次?

我只是担心多个用户一直连接和断开Shiny应用程序,如果没有正确清理,他们将留下悬空的数据库连接.实际上,客户只需关闭浏览器就可以在没有警告的情

Mat*_*rde 29

正确的方法是分配一个执行清理的功能session$onSessionEnded.例如,在server.R中:

cancel.onSessionEnded <- session$onSessionEnded(function() {
    dbDisconnect(db)
})
Run Code Online (Sandbox Code Playgroud)

然后,您可以调用cancel.onSessionEnded以撤消分配.

  • 我强烈建议不要这样做。这意味着,如果您有两名用户使用该应用程序,并且其中一名用户关闭了其选项卡,则另一名用户也会失去连接。 (2认同)

Pet*_*son 12

预先存在的答案对我来说似乎不对.

  • session$onSessionEnded可以在每个用户断开连接时关闭连接,但在原始问题中,所有用户只有一个连接.特别是在使用时pool,您不希望为每个用户启动/停止单独的连接.
  • on.exit 直接运行,而不是等到服务器退出.

我认为正确的答案是使用onStop(https://shiny.rstudio.com/reference/shiny/latest/onStop.html).

示例用法,来自文档:

library(shiny)
shinyApp(
  ui = basicPage("onStop demo"),

  server = function(input, output, session) {
    onStop(function() cat("Session stopped\n"))
  },

  onStart = function() {
    cat("Doing application setup\n")

    onStop(function() {
      cat("Doing application cleanup\n")
    })
  }
)
Run Code Online (Sandbox Code Playgroud)

  • onStop 是我一直在做的事情,它在生产中效果很好。请注意,在 Rstudio 中本地测试应用程序时,可能会导致过多的未关闭数据库连接。Rstudio“停止”按钮在停止时运行。但是,如果您正在开发应用程序并在每次更改后单击“RunApp”以重新加载应用程序,则每次都会建立一个新连接,但永远不会运行 onStop 来清理旧连接。因此,请确保在每次更改后单击“停止”,然后单击“运行应用程序”,否则您将拥有一堆僵尸数据库连接。 (2认同)

小智 6

Rstudio在6月份发布了一系列关于连接数据库的最佳实践的文章.简单的答案是使用池(参见此处此处).为简单起见,您需要定义一次池,它将处理和管理连接,根据需要打开和关闭它们.应用程序断开连接后,池将自动关闭所有连接.

不幸的是,池包不适用于SQL Server和ODBC.对于这种情况(或者,如果你不希望使用池),他们建议使用on.exit服务器函数内部小号.

例如:

getData <- reactive({
cnxn <- dbConnect(...)
on.exit(dbDisconnect(cnxn))

... # your stuff here
})
Run Code Online (Sandbox Code Playgroud)