Is it possible to stop executing of R code inside shiny (without stopping the shiny process)?

前端 未结 5 829
夕颜
夕颜 2020-12-03 03:26

Let\'s say I have a shiny app that has a function that can take a long time to run. Is it possible to have a \"stop\" button that tells R to stop the long-running call, wit

5条回答
  •  庸人自扰
    2020-12-03 03:42

    maybe also not exactly what you are looking for, but could do the trick (at least on mighty Linux). For me it works the way I want since I use bash scripts that are triggered by R shiny and I want to be able to abort them. So how about putting your R code in a script and trigger the script by the system command?

    In the example below I just use a simple dummy bash script that runs a sleep command, while the first CL argument is the amount of sleep. Everything below 10 secs is not accepted and puts the exit status to 1. In addition, I get some output in a logfile that I can monitor, and thus the progress in realtime.

    Hope you find this helpful.

    library(shiny)
    
    ui <- fluidPage(
    
    # we need this to send costumized messages
    tags$head(tags$script(HTML('Shiny.addCustomMessageHandler("jsCode",function(message) {eval(message.value);});'))),
    
    # Sidebar with a slider input for number of bins 
    sidebarLayout(
    sidebarPanel(
    
        textInput("duration", "How long you want to wait?"),hr(),
        p("Are you experienced?"),
        actionButton("processbtn", "Yes"),hr(),
        p("Show me what's going on"),
        actionButton("logbtn", "Show me by clicking here."),hr(),
        p("Tired of being experienced?"),
        actionButton("abortbtn", "Yes")
    
        ), # close sidebar panel 
    
      # Show a plot of the generated distribution
      mainPanel(
         textOutput("outText"),hr(),
         verbatimTextOutput("outLog")
      ) # close mainpanel
     ) # close sidebar
    ) # close fluidpage
    
    #------SERVER------------
    
    # Define server logic required to draw a histogram
    server <- function(input, output, session) {
    
    # our reactive values that change on button click by the observe functions below
    values <- reactiveValues(process = 0, abort = 0, log = 0)
    
    observeEvent(input$processbtn, {
      values$process = 1
      values$abort = 0
      values$log = 0
    })
    
    observeEvent(input$abortbtn, {
      values$process = 0
      values$abort = 1
    })
    
    observeEvent(input$logbtn, {
       values$log = 1
    })
    
    current_state = function(exitfile) {
    # get the pid
    pid = as.integer(system2("ps", args = "-ef | grep \"bash ~/dummy_script.sh\" | grep -v grep | awk '{print $2}'", stdout = TRUE))
    print(pid)
    
    if (length(pid) > 0)
     return("RUNNING")
    
    if (file.exists(exitfile))
     return("TERMINATED")
    
    return("NOT_STARTED")
    } 
    
    start_function = function(exitfile) {
     if(input$duration == "") {
      end_message="The text input field is empty!"
      js_string <- 'alert("SUCCESS");'
      js_string <- sub("SUCCESS",end_message,js_string)
      session$sendCustomMessage(type='jsCode', list(value = js_string)) 
      values$process = 0
      return("NOT_STARTED")
    
     } else { # all checks are fine. send a message and start processing
        end_message="We start waiting, yeah!!!"
       js_string <- 'alert("SUCCESS");'
       js_string <- sub("SUCCESS",end_message,js_string)
       session$sendCustomMessage(type='jsCode', list(value = js_string))  
    
     # here we execute the outsourced script and
     # write the exit status to a file, so we can check for that and give an error message
     system(paste("( bash ~/dummy_script.sh", input$duration,"; echo $? >", exitfile, ")"), wait = FALSE)
     return("RUNNING")
     }  
    }
    
    on_terminated = function(exitfile) {
      # get the exit state of the script
      status = readLines(exitfile)
      print(status)
      # we want to remove the exit file for the next run
      unlink(exitfile, force = TRUE)
    
      # message when we finished
      if ( status != 0 ){
        end_message="Duration is too short."
        js_string <- 'alert("SUCCESS");'
        js_string <- sub("SUCCESS",end_message,js_string)
        session$sendCustomMessage(type='jsCode', list(value = js_string))
      }
      else {
        end_message="Success"
        js_string <- 'alert("SUCCESS");'
        js_string <- sub("SUCCESS",end_message,js_string)
        session$sendCustomMessage(type='jsCode', list(value = js_string))
      }
      values$process = 0
    }
    
    # our main processing fucntion
    output$outText = renderText({
       # trigger processing when action button clicked
       if(values$process) {
    
        # get the homefolder
         homedir=Sys.getenv("HOME")
    
         # create the path for an exit file (we'll need to evaluate the end of the script)
         exitfile=file.path(homedir, "dummy_exit")
         print(exitfile)
    
         state = current_state(exitfile) # Can be NOT_STARTED, RUNNING, COMPLETED
         print(state)
         if (state == "NOT_STARTED")
            state = start_function(exitfile)
    
         if (state == "RUNNING")
            invalidateLater(2000, session = getDefaultReactiveDomain())
    
         if (state == "TERMINATED")
            on_terminated(exitfile)
    
    
    
       # Abort processing
       } else
       if(values$abort) {
          pid = as.integer(system2("ps", args = "-ef | grep \"bash ~/dummy_script.sh\" | grep -v grep | awk '{print $2}'", stdout = TRUE))
        print(pid)
        system(paste("kill", pid), wait = FALSE)
       }
    
     }) # close renderText function 
    
     output$outLog = renderText({
    
     if(values$log) {
    
       homedir=Sys.getenv("HOME")
       logfile=file.path(homedir, "/dummy_log")
    
     if(file.exists(logfile)){
       invalidateLater(2000)
       paste(readLines(logfile), collapse = "\n")
     }
     else {
       print("Nothing going on here")
     }
    }
    
    })
    
    
    } # close server
    
    # Run the application 
    shinyApp(ui = ui, server = server)
    

提交回复
热议问题