Как реализовать процедуру очистки в R Shiny?

Например, мое блестящее приложение может открыть соединение с DB

# server.R
db <- dbConnect("SQLite", DB_PATH)
shinyServer(
    ...  # things involving db
)

Теперь, как обеспечить правильное закрытие соединения db (через dbDisconnect(db)), когда заканчивается сеанс Shiny? Действительно, следует ли выполнять очистку для каждого клиента, который подключается к серверу, или только один раз?

Я просто опасаюсь, что с одновременным подключением и отключением нескольких приложений для приложения Shiny они оставят оборванные соединения DB, если они не будут правильно очищены. Действительно, клиенты могут отключиться без предупреждения, просто закрыв свои браузеры.

Ответ 1

Правильный способ сделать это - назначить функцию, выполняющую очистку с помощью session$onSessionEnded. Например, в server.R:

cancel.onSessionEnded <- session$onSessionEnded(function() {
    dbDisconnect(db)
})

Затем вы можете вызвать cancel.onSessionEnded, чтобы отменить назначение.

Ответ 2

Rstudio опубликовала серию статей в июне о лучших практиках подключения к базе данных. Простой ответ заключается в использовании пулов (см. здесь и здесь). Чтобы сделать его простым, вы определяете свой пул один раз, и он будет обрабатывать и управлять соединениями, открывая и закрывая их по мере необходимости. Когда приложение отключится, пул автоматически закроет все подключения.

К сожалению, пакет пулов не работает с SQL Server и ODBC. Для этой ситуации (или если вы не хотите использовать пул), они советуют использовать on.exit внутри вашей серверной функции s.

например:

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

... # your stuff here
})

Ответ 3

Предыдущие ответы мне не кажутся.

  • 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")
    })
  }
)

Ответ 4

Вы можете использовать on.exit(dbDisconnect(db)) внутри определения функции shinyServer.