R Shiny: async downloadHandler

Hello team,

I am seeking help with handling downloadhandler asynchronously in a shiny app. I have posted this question on stack overflow though I haven't gotten any answers yet.

Below is a reprex of how my downloadhandler looks like:

library(shiny)

ui <- fluidPage(
  downloadButton("Download", "Download")
)


server <- function(input, output){
  output$Download <- downloadHandler(
    filename = "Downloads.zip",
    content = function(file){
      withProgress(message = "Writing Files to Disk. Please wait...", {
        temp <- setwd(tempdir())
        on.exit(setwd(temp))
        files <- c("mtcars.csv", "iris.csv")

        write.csv(mtcars, "mtcars.csv")
        write.csv(iris, "iris.csv")



        zip(zipfile = file, files = files)
      })
    }
  )
}

shinyApp(ui, server)

I would love to have the app available for other users when one user clicks the download button. I've tried wrapping the write.csv inside a future function and setting `and while this does not throw an error, the app is not available for other users during the download.

I've also tried wrapping the entire downloadHandler function inside the future function, but I get the error:

Error in .subset2(x, "impl")$defineOutput(name, value, label) :
Unexpected MulticoreFuture output for DownloadUnexpected MultiprocessFuture output for DownloadUnexpected Future output for DownloadUnexpected environment output for Download

How can I handle the entire downloadHandler asyncronously? I am using the open source version of shiny server.

Wrapping write.csv in a future should work (probably the two write.csv lines and the zip line should all be in a single future). Are you sure you're using Shiny v1.2.0?

1 Like

Thanks @jcheng for pointing me in the right direction. I am on Shiny v1.2.0. However, in my actual code, I was erroneously trying to read reactive values from within a future.

After fixing this through reading the reactive values first and wrapping the write.csv and zip lines inside a single future, the app works alright, but the download doesn't happen until the second user's process is completed. (i.e., if the download normally takes 5 seconds but a second user requests a process that takes 20 seconds, the download is served after 20 seconds). I would have expected that the download is served within normal time. I am using plan(multiprocess) though I have also tried with plan(multisession). I am on linux.

So my app now looks as below:

library(future)
plan(multisession)

ui <- fluidPage(
  downloadButton("Download", "Download")
)


server <- function(input, output){
  mtcars1 <- reactive(mtcars) # These are my reactive objects
  iris1 <- reactive(iris)
  
  
  output$Download <- downloadHandler(
    filename = "Downloads.zip",
    content = function(file){
      withProgress(message = "Writing Files to Disk. Please wait...", {
        temp <- setwd(tempdir())
        on.exit(setwd(temp))
        files <- c("mtcars.csv", "iris.csv")
        
        mtcars2 <- mtcars1() # Reading my reactive values in advance of launcing the future
        iris2 <- iris1()
        
       future({
         write.csv(mtcars2, "mtcars.csv")
         write.csv(iris2, "iris.csv")
         zip(zipfile = file, files = files)
       }) 
      })
    }
  )
}

shinyApp(ui, server)

1 Like

This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.