R блестящий запуск задачи / скрипта в другом процессе

В моем приложении Shiny пользователи могут генерировать тяжелые отчеты PowerPoint. Когда он содержит много слайдов, это может занять более 30 минут. И поэтому я хотел бы обрабатывать эти задачи в независимых процессах / задачах, которые могли бы работать, даже когда приложение закрыто - например, пользователь нажимает кнопку, чтобы сгенерировать отчет, закрывает приложение и когда отчет готов, приложение информирует пользователя по электронной почте. Есть ли хорошие практики или проверенные решения для этого?

Моей первой мыслью было использование future пакет с plan(multisession) установлен - но я не уверен, что происходит, когда пользователь закрывает приложение - future сессия тоже закрывается или нет?

2 ответа

Мне посчастливилось побывать в Лондоне на этой неделе, и я думаю, что одна из лучших презентаций, которые я там увидел, была именно об этом (Джо Ченг). Для этого вам понадобится пакет обещаний, и, как сказано в документации, специальная версия блестящего devtools::install_github("rstudio/shiny@async") который поддерживает асинхронное программирование.

Вы можете найти первую документацию здесь о том, как это работает, используя dplyr а также promises (future также совместимо).

В качестве небольшого примера (взятого из документации) проведем интенсивный расчет с использованием следующего:

read.csv.async("data.csv") %...>%
  filter(state == "NY") %...>%
  arrange(median_income) %...>%
  head(10) %...>%
  View()

по существу вернет консольный курсор назад, что позволит вам запустить любую другую команду, и вы автоматически откроете View вкладка, как только это было закончено. Возможно, мне удастся немного разглядеть блестящий пример, но имейте в виду, что он все еще находится в стадии разработки и будет выпущен до конца года (с более полной документацией, которую я мог бы представить).

Таким образом, я сделал несколько примеров, используя future пакет. Код выполняется в отдельном сеансе (кластере), даже когда приложение закрыто. Я думаю, что следующий шаг - просто выяснить, как приложение должно проверять, запущен ли процесс или завершен. Есть идеи?

library(future)
cl <- parallel::makeCluster(2L)
plan(cluster, workers = cl)

server <- function(input, output) {
  observeEvent(input$run, {

    iteration <- as.numeric(input$iteration)
    path <- input$path

    future::future({
      writeLog <- function(n, path) {
        file.remove(path)
        for (i in 1:n) {
          cat("#", i, "-",  as.character(Sys.time()), "\n", file = path, append = TRUE)
          Sys.sleep(1)
        }
      }
      writeLog(iteration, path)
    }, globals = c("iteration", "path"))
  })
}

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      tags$div("This app writes to file in cluster which means it is computed in parallel to this session. 
               It will execute even when app is closed.")
      , br()
      , shiny::textInput("path", "Path to log file", value = "/src/dev/export_performance/future.log")
      , shiny::textInput("iteration", "Iteration number", value = 60)    
    ),
    mainPanel(
      br()
      , actionButton("run", "Run future")
    )
  )
)

shinyApp(ui = ui, server = server)
Другие вопросы по тегам