Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R shiny future: plan(multiprocess)/plan(multicore) + Kill long running process

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.

like image 807
chas Avatar asked Nov 05 '18 09:11

chas


1 Answers

A couple problems here:

  1. You are missing library(promises), plan(multicore) and library(ipc).
  2. fut is not a future, it is a promise because of the %...>%, so stopMulticoreFuture won't work on it.
  3. The ObserveEvent expression needs to return something other than the promise, otherwise your UI will block.
  4. Since 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.
like image 86
Ian Fellows Avatar answered Nov 09 '22 21:11

Ian Fellows