Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Invoke interrupt from R code

Tags:

r

try-catch

I have a generic function to catch all exceptions included in my package logR::tryCatch2 defined as:

tryCatch2 <- function(expr){
    V=E=W=M=I=NULL
    e.handler = function(e){
        E <<- e
        NULL
    }
    w.handler = function(w){
        W <<- c(W, list(w))
        invokeRestart("muffleWarning")
    }
    m.handler = function(m){
        attributes(m$call) <- NULL
        M <<- c(M, list(m))
    }
    i.handler = function(i){
        I <<- i
        NULL
    }
    V = suppressMessages(withCallingHandlers(
        tryCatch(expr, error = e.handler, interrupt = i.handler),
        warning = w.handler,
        message = m.handler
    ))
    list(value=V, error=E, warning=W, message=M, interrupt=I)
}

As you can see in the last line it returns a list which is more or less self describing.
It makes the real reaction to the exceptions delayed after the tryCatch2 call by simple !is.null:

f = function(){ warning("warn1"); warning("warn2"); stop("err") }
r = tryCatch2(f())
if(!is.null(r$error)) cat("Error detected\n")
# Error detected
if(!is.null(r$warning)) cat("Warning detected, count", length(r$warning), "\n")
# Warning detected, count 2 

It works as expected, I can react with my own code. But in some cases I would like to not stop the interrupt process which is caught too. At the moment it seems I would need to add additional parameter to tryCatch2 which would control if interrupts should be catch or not. So the question asks about some invokeInterrupt function which I could use in the following way:

g = function(){ Sys.sleep(60); f() }
r = tryCatch2(g())
# interrupt by pressing ctrl+c / stop while function is running!
if(!is.null(r$interrupt)) cat("HERE I would like to invoke interrupt\n")
# HERE I would like to invoke interrupt

I think if R is able to catch one it should be also able to invoke one.
How can I achieve invokeInterrupt functionality?

like image 464
jangorecki Avatar asked Sep 28 '15 10:09

jangorecki


People also ask

How do I interrupt in RStudio?

However, if you are using RStudio on a Windows computer, you can usually use Esc to stop a currently executing R script. Then, we can press Esc to interrupt the loop.

How do I stop an R code from running?

In R Studio, Rgui, and R. APP, pressing the Esc key interrupts the running code. R Studio also offers a Stop button and a menu option to stop running code with the mouse. In the R command-line interface, the Ctrl + C command stops the execution of the code.

What does terminate R do?

Terminating R will cause your R session to immediately abort. Active computations will be interrupted and unsaved source file changes and workspace objects will be discarded.


2 Answers

I can propose a partial solution, which relies on the tools package.

invokeInterrupt <- function() {
  require(tools)
  processId <- Sys.getpid() 
  pskill(processId, SIGINT)
}

However, be aware that throwing the interrupt signal (SIGINT) with pskill doesn't appear to be very robust. I ran a few tests by sending the exception and catching it with your function, like so:

will_interrupt <- function() {
    Sys.sleep(3)
    invokeInterrupt()
    Sys.sleep(3)
}

r = tryCatch2(will_interrupt())

On linux, this worked well when executed from the R commandline. On windows, the R commandline and R Gui did close when executing this code. There is worse: on both linux and windows, this code crashed Rstudio instantly...

So, if your code is to be executed from the R commandline on Linux, this solution should be OK. Otherwise you might be out of luck...

like image 68
Jealie Avatar answered Sep 27 '22 20:09

Jealie


Late answer but I have found that rlang::interrupt can throw "user interrupts":

interrupt() allows R code to simulate a user interrupt of the kind that is signalled with Ctrl-C. It is currently not possible to create custom interrupt condition objects.

Source: ?rlang::interrupt

Internally it calls the R API function Rf_onintr which is an alias for the function onintr.

Basically an interrupt is "just" a special condition with these classes: interrupt and condition (see the R source code).

If you just want to simulate an interrupt to test tryCatching (without the need to interrupt a running R statement) it suffice to throw a condition with these classes via signalCondition:

interrupt_condition <- function() {
  structure(list(), class = c("interrupt", "condition"))
}

tryCatch(signalCondition(interrupt_condition()),
                         interrupt = function(x) print("interrupt detected"))
# [1] "interrupt detected"
like image 25
R Yoda Avatar answered Sep 27 '22 20:09

R Yoda