R Shiny在不同的过程中运行任务/脚本

时间:2022-08-06 13:54:46

In my Shiny app users can generate heavy powerpoint report. When it contains a lot of slides it could take > 30 minutes to be done. And therefore I'd like to process those tasks in independent processes/tasks which could work even when app is closed - e.g. user clicks button to generate report, closes app and when report is ready app informs user by email. Are there any good practices or proven solutions to do this?

在我的Shiny应用程序中,用户可以生成重型powerpoint报告。当它包含大量幻灯片时,可能需要30分钟才能完成。因此,我想在独立的流程/任务中处理这些任务,即使应用程序关闭也可以工作 - 例如用户单击按钮生成报告,关闭应用程序,当报告准备好时,应用程序通过电子邮件通知用户。是否有任何良好做法或经过验证的解决方案?

My first thought was using future package with plan(multisession) set - but I'm not sure what happens when user closes the app - future session closes too or not?

我的第一个想法是使用计划(多会话)设置的未来包 - 但我不确定当用户关闭应用程序时会发生什么 - 未来的会话也会关闭?

2 个解决方案

#1


9  

I was lucky enough to be at London EARL this week and I think one of the best presentations I saw there was about exactly this (by Joe Cheng). You would need the promises package for this to work and as it says on the documentation a special version of shiny devtools::install_github("rstudio/shiny@async") that supports asynchronous programming.

我很幸运能够在本周参加伦敦EARL,我认为我在那里看到的最好的演讲之一就是(Joe Cheng)。你需要promises包才能工作,正如文档中所说,支持异步编程的特殊版本的闪亮devtools :: install_github(“rstudio / shiny @ async”)。

You can find a first documentation here on how this works by using dplyr and promises (future is also compatible).

您可以通过使用dplyr和promises(未来也兼容)在此处找到有关其工作原理的第一个文档。

As a small example (taken from the documentation), running an intensive calculation using the following:

作为一个小例子(取自文档),使用以下代码运行密集计算:

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

would essentially return the console cursor back, allowing you to run any other command you want and would automatically open the View tab once this was finished. I might be able to dig out a shiny example in a bit, but keep in mind this is still under development and will be released before the end of the year (with a more comprehensive documentation I would imagine).

本质上会返回控制台光标,允许您运行所需的任何其他命令,并在完成后自动打开“视图”选项卡。我可能会稍微挖掘出一个闪亮的例子,但请记住,这仍然在开发中,并将在今年年底之前发布(我想象的更全面的文档)。

#2


1  

So I made some example workaround using future package. Code executes in separate session (cluster) even when app is closed. I think the next step is just to figure out how app should check if process is still running or is finished. Any ideas?

所以我使用未来的包做了一些示例解决方法。即使应用程序关闭,代码也会在单独的会话(群集)中执行。我认为下一步就是弄清楚app应该如何检查进程是否仍在运行或已完成。有任何想法吗?

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)

#1


9  

I was lucky enough to be at London EARL this week and I think one of the best presentations I saw there was about exactly this (by Joe Cheng). You would need the promises package for this to work and as it says on the documentation a special version of shiny devtools::install_github("rstudio/shiny@async") that supports asynchronous programming.

我很幸运能够在本周参加伦敦EARL,我认为我在那里看到的最好的演讲之一就是(Joe Cheng)。你需要promises包才能工作,正如文档中所说,支持异步编程的特殊版本的闪亮devtools :: install_github(“rstudio / shiny @ async”)。

You can find a first documentation here on how this works by using dplyr and promises (future is also compatible).

您可以通过使用dplyr和promises(未来也兼容)在此处找到有关其工作原理的第一个文档。

As a small example (taken from the documentation), running an intensive calculation using the following:

作为一个小例子(取自文档),使用以下代码运行密集计算:

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

would essentially return the console cursor back, allowing you to run any other command you want and would automatically open the View tab once this was finished. I might be able to dig out a shiny example in a bit, but keep in mind this is still under development and will be released before the end of the year (with a more comprehensive documentation I would imagine).

本质上会返回控制台光标,允许您运行所需的任何其他命令,并在完成后自动打开“视图”选项卡。我可能会稍微挖掘出一个闪亮的例子,但请记住,这仍然在开发中,并将在今年年底之前发布(我想象的更全面的文档)。

#2


1  

So I made some example workaround using future package. Code executes in separate session (cluster) even when app is closed. I think the next step is just to figure out how app should check if process is still running or is finished. Any ideas?

所以我使用未来的包做了一些示例解决方法。即使应用程序关闭,代码也会在单独的会话(群集)中执行。我认为下一步就是弄清楚app应该如何检查进程是否仍在运行或已完成。有任何想法吗?

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)