I am writing this to seek some help in using plan(multiprocess) or plan(multicore) and killing long running processes in my shiny app. The app has multiple future events (long running processes) that run on clicking their corresponding actionButton. Below is an example app of future() command used within the server function in the app. And i have been using stopMulticoreFuture(fut) to kill the processes.
library(shiny)
library(shinydashboard)
library(promises)
plan(multicore)
library(ipc)
sidebar <- dashboardSidebar(width = 200, sidebarMenu(id = "tabs",
menuItem("File", tabName = "tab1", icon = icon("fas fa-file"))))
body <- tabItem(tabName = "tab1",h2("Input File"),
fluidRow(tabPanel(
"Upload file",
value = "upload_file",
fileInput(
inputId = "uploadFile",
label = "Upload Input file",
multiple = FALSE,
accept = c(".txt")
),
checkboxInput('header', label = 'Header', TRUE)
),
box(
title = "Filter X rows",
width = 7,
status = "info",
tabsetPanel(
id = "input_tab",
tabPanel(
"Parameters",
numericInput(
"nrows",
label = "Entire number of rows",
value = 5,
max = 10
),
actionButton("run", "Analyze"),
actionButton("cancel", "Cancel")
),
tabPanel(
"Results",
value = "results",
navbarPage(NULL,
tabPanel(
"Table", DT::dataTableOutput("res_table"),
icon = icon("table")
)),
downloadButton("downList", "Download")
)
)
)
))
ui <-
shinyUI(dashboardPage(
dashboardHeader(title = "TestApp", titleWidth = 150),
sidebar,dashboardBody(tabItems(body))
))
server <- function(input, output, session) {
file_rows <- reactiveVal()
observeEvent(input$run, {
prog <- Progress$new(session)
prog$set(message = "Analysis in progress",
detail = "This may take a while...",
value = NULL)
file_nrows <- reactive({
return(input$nrows)
})
file_nrows_value <- file_nrows()
file_input <- reactive({
return(input$uploadFile$datapath)
})
file_input_value <- file_input()
fut<- NULL
fut<<- future({system(paste(
"cat",
file_input_value,
"|",
paste0("head -", file_nrows_value) ,
">",
"out.txt"
))
head_rows <- read.delim("out.txt")
head_rows
}) %...>%
file_rows() %>%
finally(~prog$close())
})
observeEvent(file_rows(), {
updateTabsetPanel(session, "input_tab", "results")
output$res_table <-
DT::renderDataTable(DT::datatable(
file_rows(),
options = list(
searching = TRUE,
pageLength = 10,
rownames(NULL),
scrollX = T
)
))
})
output$downList <- downloadHandler(
filename = function() {
paste0("output", ".txt")
}, content = function(file) {
write.table(file_rows(), file, row.names = FALSE)
}
)
observeEvent(input$cancel,{
stopMulticoreFuture(fut)
})
}
shinyApp(ui = ui, server = server)
When i click "Cancel" button, the UI gets disabled but the console shows the below warning and the command still gets executed in the console.
Warning: Error in stopMulticoreFuture: stopMulticoreFuture only works on multicore futures
Since this example represents a quick running process the future() command gets executed before clicking Cancel
.
In real case, even after clicking “Cancel” the command inside the future (long process) still runs in the console after the warning while the UI is already disabled.
The app is currently run on MAC with 4 cores. How could i kill the process running in the console rather just getting the UI disabled?
I am currently testing my app and would be great to have expert input in planning multiprocess/multicore and killing the processes to make the app efficient for running async processes among parallel users. The final app will be running on Ubuntu machine with 4 virtual CPUs.
A couple problems here:
library(promises)
, plan(multicore)
and library(ipc)
.fut
is not a future, it is a promise because of the %...>%
, so stopMulticoreFuture
won't work on it. ObserveEvent
expression needs to return something other than the promise, otherwise your UI will block.stopMulticoreFuture
just kills the process, I can't assure you that it will work with system
calls that create subprocesses. You may need to figure out the pid values for these and kill them yourself.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With