Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rserve server: how to terminate a blocking instance (eval taking forever)?

I need to perform R evals in a multi-threaded way, which is something Rserve provides quite well. But, if the eval of one instance takes too long, I need to be able to shutdown the instance which is computing the blocking eval. As far as I tested, the given instance will refuse to shutdown until the eval is done (apparently, it needs to fetch the result, before listening again). So here is my question:

Is there a way get a java handle on the blocking instance (something like a Process object), such that I can brute force kill/terminate the eval (something like process.destroy())? In other words, when I ask for an eval (create a connection, throw a command), how do I establish a relationship between the eval being processed, and the instance of Rsere related to it, via java?

Or did I miss something about Rserve which already allows to deal with this kind of needs?

Note: I already tried to run everything (all evals) via serverEval() instead of the regular eval, which runs the computations on the main instance, but this is, of course, not satisfying as it uses only one process (the main one). That one I can kill, but my main goal was to be able to shutdown individually a blocking eval, running on an individual instance. And, naturally, keep advantage of my 8 CPU cores, that is to say, preserve the parallelism. There is no point to use Rserve otherwise (JRI engine would be more than sufficient in this case).

Note: I would like to avoid this kind of things (thread), dealing with several instances of the main server itself, on different ports. That is not an option.

I already tried getting information on Rserve's mailing list, but haven't been answered. I hope I made myself clear enough to get an answer or helpful comment here. If not, please ask for details. Thanks so much by advance.

Edit: I also tested RCaller, which deals with as many instances of R one need, but, as it is writing results into XML files for later parsing from java side (not really using a communication protocol as Rserve would), it is far too slow for what I have to perform...

like image 771
Gauthier Boaglio Avatar asked Nov 21 '14 17:11

Gauthier Boaglio


1 Answers

OK, this can be done this way (caught it from some nice person who finally answered me on Rserve devel mailing list):

In the thread running the eval supposed to be blocking or too long, and assuming Rserve is started:

private RConnection rEngine = null;
private int rServePid = -1;

//...

// Keep an opened instance and store the related pid
RConnection rconn = new RConnection();
this.rServePid = rconn.eval("Sys.getpid()").asInteger();
this.rEngine = rconn;
LOG.info("Rserve: started instance with pid '" + this.rServePid + "'.");
//...
this.rEngine.eval("some consuming code...");

Which allows to keep track of the pid of the instance related to the said eval (R privides Sys.getpid()).

Then to stop / abort / cancel and since a simple this.rEngine.close() will not stop the task being processed on server side, but only close the connection, we need to kill the targeted Rserve instance. This can be done by calling tools::pskill() (or any other system call like possibly kill -9 my_pid (UNIX*), TASKKILL /PID my_pid /F (Windows), ..., depending on the platform), obviously from another thread than the one above (which is waiting for the "eval part" to return):

// Terminate.
RConnection c2 = new RConnection();
// SIGTERM might not be understood everywhere: so using SIGKILL signal, as well.
c2.eval("tools::pskill("+ this.rServePid + ")");
c2.eval("tools::pskill("+ this.rServePid + ", tools::SIGKILL)");
c2.close();
LOG.info("Rserve: terminated instance with pid '" + this.rServePid + "'.");

That one has the benefit to be plateform independent.

Hope this can help.

like image 104
Gauthier Boaglio Avatar answered Sep 21 '22 13:09

Gauthier Boaglio