I tried to do this with shiny promises / async.
Partial success I think, you do see reactive reads between the start and completion, and in my setup with non-async times to take 7.5 seconds to finish, the async version gives all the results within about half that time.
library(shiny)
library(future)
library(stringr)
library(promises)
plan(multisession)
num_to_do <-10
slowfunc <- function(x,file){
Sys.sleep(.75)
write(x=paste0("tofile status = ", x),file = file,append=TRUE)
cat(paste0("tolog status = ", x, "\n"))
}
slowfunc.async <- function(x,file){
cat(paste0("entered async with x of ", x,"\n"))
x
future_promise({
Sys.sleep(.75)
}) %...>% {
NULL
write(x=paste0("tofile status = ", x),file = file,append=TRUE)
cat(paste0("tolog status = ", x, "\n"))
}
}
ui <- fluidPage(
h3("My process logs:"),
verbatimTextOutput("t_elapse"),
shiny::selectInput("useAsync","use Async?",choices = c(FALSE,TRUE)),
actionButton("debug","debug"),
actionButton("start","start"),
htmlOutput("mylog")
)
server <- function(input, output, session) {
# create temp log file
logfile_tmp <- tempfile(fileext = ".log")
file.create(logfile_tmp)
start_time <- reactiveVal(NULL)
end_time <- reactiveVal(NULL)
output$t_elapse <- renderPrint({
s <- start_time()
e <- end_time()
if(isTruthy(s) && isTruthy(e))
difftime(e,s) else {
"press start"
}
})
observeEvent(input$debug,
browser())
# send temp log to UI twice per second
mylog <- reactiveFileReader(500, session, logfile_tmp, readLines)
myloghtml <- reactive({
slog <- sort(req(mylog()))
HTML(paste(slog, collapse = '<br/>'))
})
output$mylog <- renderUI({
req(myloghtml())
})
# some basis for judging completion of logging task
observeEvent(mylog(), {
if (identical(
req(myloghtml()),
HTML(paste0(paste0("tofile status = ", str_pad(1:num_to_do,2,pad = 0)),
collapse = "<br/>"
))
)) {
end_time(Sys.time())
}
})
observeEvent(input$start,
{
start_time(Sys.time())
end_time(NULL)}
)
observeEvent (input$useAsync, # for resetting
end_time(NULL))
observeEvent(start_time(),{
file.create(logfile_tmp)
# fill temp log file with the console output of some time intensive computation
# start time intensive computation
for (i in 1:num_to_do) {
ipad <- str_pad(i,2,pad = 0)
if(input$useAsync)
slowfunc.async(ipad,logfile_tmp)
else
slowfunc(ipad,logfile_tmp)
}
})}
shinyApp(ui, server)