Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make an operation uninterruptible in R shiny

Tags:

r

shiny

In my shiny app I have a output which should update itself continuously. But whenever I execute a long-running calculation, the output is just paused. My question is: how to make the output runs continuously and uninterruptible?

Please see the short demo below: The clock refreshes every one second, but if I click the button which runs for 5 seconds, the clock is paused.

library(shiny)

ui <- fluidPage(
    actionButton("button","Expensive calcualtion(takes 5 seconds)"),
    tags$p("Current Time:"),
    textOutput("time"),
    tags$p("Result from clicking button:"),
    textOutput("result")
)

server <- function(input, output, session) {
    output$time <- renderText({
        invalidateLater(1000)
        as.character(Sys.time())
    })

    observeEvent(input$button,{
        Sys.sleep(5)
        output$result <- renderText(runif(1))
  })
}

shinyApp(ui, server)

I tried to use future and promises to make the long-running process runs asynchronously, but it doesn't work. Where is wrong? And is there a better way for achieving this purpose?

library(shiny)
library(future)
library(promises)
plan("multisession")

ui <- fluidPage(
    actionButton("button","Expensive calcualtion(takes 5 seconds)"),
    tags$p("Current Time:"),
    textOutput("time"),
    tags$p("Result from clicking button:"),
    textOutput("result")
)

server <- function(input, output, session) {
    output$time <- renderText({
        invalidateLater(1000)
        as.character(Sys.time())
    })

    process <- eventReactive(input$button,{
        future({
            Sys.sleep(5)
            runif(1)
        })
    })

    output$result <- renderText(process())

}

shinyApp(ui, server)

Any help is appreciated!

like image 953
yusuzech Avatar asked Sep 12 '19 19:09

yusuzech


1 Answers

Thanks @Shree for pointing out the solution. After reading the response from Joe Cheng. It seems like the key is to:

Hide the async operation from Shiny by not having the promise be the last expression.

The problem is resolved by creating a reactive value and assign the promise to it in observeEvent as the side effect.

server <- function(input, output, session) {

  output$time <- renderText({
    invalidateLater(1000)
    as.character(Sys.time())
  })

  process <- reactiveVal()

  observeEvent(input$button,{
    output$isbusy <- renderText("busy") # a simple busy indicator
    future({
      Sys.sleep(5)
      runif(1)
    }) %...>%
      process()
    # Hide the async operation from Shiny by not having the promise be the last expression
    NULL # important
  })

  output$result <- renderText({
    output$isbusy <- renderText("") # a simple busy indicator
    process()
  })
}
like image 122
yusuzech Avatar answered Sep 25 '22 19:09

yusuzech