I am working on an application that needs to launch a process and wait for its output. Sometimes the process crashes (very often,) but is not really an issue since I have mitigation tasks. The problem is that Windows detects the process crashed and prompts for user input, to either check for a solution online, or just close the program.
I tried to solve this by waiting for the process to complete in a Runnable submitted to an ExecutorService and using the Future returned to specify a timeout. Speed is not really a concern for the application, and the external process is supposed to run for just a couple of seconds.
This is the code I am using:
final Process process = ...
final ExecutorService service = Executors.newSingleThreadExecutor();
try {
final Future<?> future = service.submit(new Runnable() {
#Override
public void run() {
try {
process.waitFor();
} catch (InterruptedException e) { /* error handling */}
}
});
future.get(10, TimeUnit.SECONDS);
} catch (final TimeoutException e) {
// The process may have crashed
process.destroy();
} catch (final Exception e) {
// error handling
} finally {
service.shutdown();
}
The code above worked well, but the crash dialog still pops up and it doesn't go away without user interaction.
This question presents a similar problem but from a .Net perspective and
proposes to suppress the pop up through the Windows registry, which I cannot do, given that its effect is global to all process in the machine.
Is there a way to prevent the dialog from being displayed at all?
or
Is there a way to detect the application crash and handle it directly
from Java without needing user interaction?
Additional details:
I don't have the source of the external process.
The external process is a console based application (i.e. no GUI.)
Preferably I'm looking for a pure Java based solution (no JNI.)
Thank you.
As already suggested you should use SetErrorMode win32 call. It won't change for the whole system but only for your process and it's children (which is what you want apparently).
The correct call seems to be :
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
See also the MSDN documentation :
http://msdn.microsoft.com/en-us/library/windows/desktop/ms680621%28v=vs.85%29.aspx
Regards.
Related
The service I'm working on uses a Future to run multiple tasks in parallel; each task can take up to a minute to complete. However, it seems the external lib is buggy, since in some occasions (2% of the time) it doesn't return. In those cases I would like to give a 2-minute wait time, and if it hasn't returned, I would like to kill the future and re-schedule again later (it will succeed eventually).
How do I kill the Future?
private void run() {
ExecutorService queue = Executors.newFixedThreadPool(1);
Future<Integer> f = queue.submit(new MyTask());
Thread.sleep(500);
try {
Integer r = f.get(120, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
e.printStackTrace();
f.cancel(true);
}
// Bad future still running here and I need it dead.
}
private class MyTask implements Callable<Integer> {
private ExternalLibrary extlib = new ExternalLibrary();
#Override
public Integer call() throws Exception {
// step 1 - do a few things
// step 2 - process data
Integer val = this.extlib.doSomething(); // here's the problem!
// step 3 - do other things
return val;
}
}
I can see the external lib running and consuming CPU (for 24 hours)... doing nothing. It's a simple task that should never take more than 60 seconds to complete its work.
So far, I'm killing the whole JVM once a day to get rid of this issue, but I'm sure there must be a better way. I wonder how app servers (Tomcat, JBoss, Weblogic, etc.) do it with rogue processes.
Even if you could kill the future hanging in the buggy library, this does likely not solve your problem. The library might still have acquired some resource which will not be properly clean up. This might be memory allocations, open file handles or even monitors leaving some internal data structures in an inconsistent state. Eventually you will likely be back at the point where you have to restart your JVM.
There's basically two options: Fix or isolate it.
Fix: try to get the library fixed. If this is not possible,
isolate: isolate the library into a external service your application depends on. E.g. implement a REST API for calling the library and wrap everything up into a Docker image. Automate restarting of the Docker container as needed.
As others have mentioned, stopping a Future is cooperative, meaning, the thread running async must respond to cancellation from the waiting thread. If the async task isn't cooperative simply invoking shutdown or shutdownNow won't be enough as the underlying TPE will just interrupt the threads.
If you have no control over extlib, and extlib is not cooperative, I see two options
You can stop the thread currently running. This can cause issues if the thread being stopped currently is holding a lock or some other resource. It can lead to interesting bugs that could be hard to dissect.
This could take some more work, but you could run the async task as a separate process entirely. The TPE can still run the process and, on interruption, can destroy the process. This obviously has more interesting issues like how to load the process with required input.
If I understand your requirement correctly & based on your requirement (i.e. 1 thread), you can look for shutting down executorservice in 2 phases, code is available in java doc of executorservice:
try {
Integer r = f.get(120, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
e.printStackTrace();
//f.cancel(true); you can omit this call if you wish.
shutdownAndAwaitTermination(queue);
} ... //remaining method code
void shutdownAndAwaitTermination(ExecutorService pool) {
pool.shutdown(); // Disable new tasks from being submitted
try {
// Wait a while for existing tasks to terminate
if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
pool.shutdownNow(); // Cancel currently executing tasks
// Wait a while for tasks to respond to being cancelled
if (!pool.awaitTermination(60, TimeUnit.SECONDS))
System.err.println("Pool did not terminate");
}
} catch (InterruptedException ie) {
// (Re-)Cancel if current thread also interrupted
pool.shutdownNow();
// Preserve interrupt status
Thread.currentThread().interrupt();
}
}
Please read documentation about shutdown() , shutdownNow() how they behaves because it clearly mentions there is no 100% guarantee that tasks / executorservice will get stopped if its running.
Unfortunately if the external library is not co-operating to thread interrupts, there is nothing you can do to kill the Thread running the task managed by the ExecutorService.
An alternative that I can think of is to run the offending code as a separate process. Using ProcessBuilder and Process, your task can effectively control (or) even kill the offending process after a timeout (https://docs.oracle.com/javase/9/docs/api/java/lang/Process.html#destroyForcibly--).
Also see https://docs.oracle.com/javase/9/docs/api/java/lang/ProcessBuilder.html
#joe That is correct. Unless you have control over the thread and inside the thread you can't kill it.
this.extlib.doSomething();
if this line starts a thread then we need to get hold of that thread to kill it as we don't have reference to stop it.
In your code, the call:
this.extlib.doSomething()
must be synchronous, because if it is not, the code lost sense. With that assumption, you can try:
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Integer> future = executor.submit(new MyTask());
try {
future.get(120, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
future.cancel(true);
} finally {
executor.shutdownNow();
}
If this doesn't stop the doSomethig work is because this doSomething function is opening other threads to do the work. In that case, maybe you can check the threads that are running with:
Thread.getAllStackTraces()
And try to kill the right one...
I have the following code:
public class LogWriter implements Runnable {
private static BlockingQueue<LogRecord> logQueue;
static {
logQueue = new ArrayBlockingQueue<LogRecord>(30);
}
#Override
public void run() {
Integer errorNo = 0;
configureLogger();
while (true) {
try {
LogRecord record = logQueue.take();
consumeLogRecord(record);
System.out.println(++errorNo + " - Logged error in file '" + LoggerConfig.LOG_PATH + "'");
record = null;
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
}
}
}
This is part of a logger for a LibreOffice pluggin written in Java. When LibreOffice is closing, it simply kills it's plugins (as I can tell so far, not sure of it), but not before sending a signal to them that it is closing, which I can detect in my code (through the UNO API). After I receive the termination signal from LibreOffice, I want to flush my LogRecord queue to the log file and change that while(true) to false so the method run() can finish appropriately, releasing the resources it have. So my question is, how can I tell the JVM that waiting for this operation is of high priority and it shouldn't terminate before finishing it?
The advice about shutdown hooks must be taken with a large grain of salt. The shutdown hook is a last resort device where you can try to salvage what you couldn't possibly by any other means. You can't rely on any normal assumption, such as that System.out is still open, that your log file is still open, that even the filesystem is available, and so on.
A use case for a shutdown hook is to try to gracefully close acquired resources, with no attempt at further data transfer.
The approach you should take is:
inform yourself exactly what terms LibreOffice gives you: do you have a certain timeout within which to complete your work?
minimize the work pending at any point in time, thereby maximizing your chance to have it completed within the timeout.
You can use.
Runtime.getRuntime().addShutdownHook(Thread);
Shutdown hooks will be the best option to go.
I am trying to execute external jar from java app.
What is the most elegant way to check if the process has been started successfully and running?
ExtApp.jar is long-term running process, so I can not use Process.waiFor() because it would block my app. I have come up with following code, with idea behind is that the exitValue() throws IllegalThreadStateException if the process has not been yet terminated.
boolean success = false;
try {
Process process = Runtime.getRuntime().exec("java -jar ExtApp.jar");
try {
if (process.exitValue() == 0)
success = true;
} catch (IllegalThreadStateException e) {
success = true;
}
} catch (Exception e) {}
System.out.println(success);
But it is kind of ugly solution. Any ideas for a better one?
There seems to be no elegant solution to the problem. E.g. I ran your code on my PC and got "success" though there is no ExtApp.jar on it. That is, from the point of view of Runtime.exec the process (java.exe) started successfully, no matter what happens afterwards.
The above seems very dubious. You're going to spawn off your process and then test it immediately. The process itself may not have determined whether it's running ok or not (e.g. when does it actually check that jar file eixsts/is loadable/is valid ?)
I think you're better off spawning the process via a new thread, calling/blocking in that thread via Process.waitFor() and then notifying the parent thread (via whatever means - state variable, wait()/notify(), a java.util.concurrent.Future etc.) once the process has exited and you've collected the exit status.
Apache Commons Exec is a useful library for doing this sort of work, including asynchronous spawning/notification of process exit. See the DefaultExecuteResultHandler for more info.
I was going through shutdown hook feature of java , My analysis was ..shutdownhook allows to register a thread that will be created immediatly but started only when the JVM ends ! So it is some kind of "global jvm finalizer", and you can make useful stuff in this thread (for example shutting down java ressources like an embedded hsqldb server). This works with System.exit(), or with CTRL-C / kill -15 (but not with kill -9 on unix, of course).
Please advise more practical uses and please also if possibe an small example will help to make understanding more clear..!
When a shutdown hook is added to a Runtime instance, it is added to a list of Threads to start upon clean termination of the JVM.
Example: Using shutdown hook to ensure that a java.awt.TrayIcon is removed from the system tray.
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
try {
if (SystemTray.isSupported()) {
SystemTray.getSystemTray().remove(yourTrayIcon);
}
} catch (Exception e) {
// failed to remove
e.printStackTrace();
}
}
});
More can be read in the offical documentation.
I have made a java application and have packed it into an executable jar file. Now a user can start that program from either of the following two ways:
Start if from command prompt by executing the following command on the command prompt:
java -jar "MyJar.jar"
By double clicking on that jar file.
I want that my client would adopt second approach as it is much easier than the first approach. But the problem with second approach is how to stop application before it has finished?
It is a command-line application.
And no command prompt window appears when a user double clicks on the jar file. So in this case, Will Ctrl + c work?
Stopping (exiting) the application should be inside the application. Whether it is command line or GUI based, the application developer should write code to exit it (For eg., in a command line application you might have something like Press 5 to exit, Press Esc to Exit etc) and in an application with a GUI, you will have to write code to exit when the window is closed, or an EXIT button (or others, depending on your application)
Ctrl + C is KILL the application. This is not a Normal exit. For apps with a GUI, the user would typically (in Windows) go to task manager and end the process (similar ways in other operating systems)
But these are abnormal exits - when the user wants to kill the app when, for instance, the application is no longer responding. Normal exits should be provided by the application (and therefore by the programmer - you)
I've had a similar problem. I have some Java programs that are basically long-running daemon processes. It's nice to be able to stop them and bounce (restart) them.
I've used two approaches. Both have advantages and disadvantages. One is to set up a signal handler, by putting a function like this in some class of your program (in mine, it's in the class with the main method).
import sun.misc.Signal;
import sun.misc.SignalHandler;
...
private static boolean stopNow = false;
private static boolean restartNow = false;
...
private static void handleSignals() {
try {
Signal.handle(new Signal("TERM"), new SignalHandler() {
// Signal handler method for CTRL-C and simple kill command.
public void handle(Signal signal) {
MyClass.stopNow = true;
}
});
}
catch (final IllegalArgumentException e) {
logger.warn("No SIGTERM handling in this instance.");
}
try {
Signal.handle(new Signal("INT"), new SignalHandler() {
// Signal handler method for kill -INT command
public void handle(Signal signal) {
MyClass.stopNow = true;
}
});
}
catch (final IllegalArgumentException e) {
logger.debug("No SIGINT handling in this instance.");
}
try {
Signal.handle(new Signal("HUP"), new SignalHandler() {
// Signal handler method for kill -HUP command
public void handle(Signal signal) {
MyClass.restartNow = true;
}
});
}
catch (final IllegalArgumentException e) {
logger.warn("No SIGHUP handling in this instance.");
}
}
This has worked robustly for us in production. You need a genuine Sun JRE for this to work; the one shipped with a typical Linux distro doesn't have the Signal stuff in it. It works OK on Windows too, but you don't get the HUP signal. You do need a shortcut or shellscript to launch this thing.
Also, keep in mind that signal handling is a big fat botch. Don't try to do very much inside your signal handler. You can see that my sample code simply sets static flags. Other parts of my program detect that the flag changed, and shut down. I could have experimented with more complex code inside the signal handler, but I didn't feel like taking on the QA burden.
The other approach is to structure your program as a Servlet. You'll write a class that extends HttpServlet in this case. Override Servlet.init with a method that starts your worker thread. Likewise, Override Servlet.destroy with a method that shuts yourself down.
Then you can use a Java EE container server like Tomcat to manage your starting and stopping.
If your program is a console mode program and it's doing output, Ctrl-C should be able to kill it.
If it's a GUI program, you'll want to give it a button to exit, or at least setting EXIT_ON_CLOSE as the defaultCloseOperation of your main JFrame.
ctrl+alt+suppr -> kill the javaw.exe ? :p
Or you would have to present a user interface with a stop button (see swing etc)
It depends on the User Interface. If its a Swing application then you can setDefaulCloseOperation(JFrame.EXIT_ON_CLOSE) on your main Frame. If its a console app and the user is interacting with it then you ask the user to enter a value that indicates to you that they want to stop the app. If yoy are not interacting with the user at all then ctrl-c will have to work.
Is it a GUI application or commandline.
In first case just handle the window closing event. In second case handle e.g. CTRL + C
that depends on what kind of application is it?
Is it a swing application? If so, then your app should handle when user clicks the 'close' button. There is a behavior for that. JFrame.close()
If it isnt a swing app then ctrl+c will work.
"It is a command-line application" you say.. Well you could do it so that when the user hit a button (say esc) he can write short commands to exit, restart etc..
You can do this with KeyListener. When ESC is hit (say that is the button you want the user to hit), you use Scanner on System.in, and you will do a System.exit(0); if the input is "exit".
I've used socket connection to enable kill of running instance.
//send kill signal to running instance, if any
try {
new Socket("localhost", 4000).getInputStream().read(); //block until its done
} catch (Exception e) { //if no one is listening, we're the only instance
}
//start kill listener for self
new Thread() {
#Override
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(4000);
serverSocket.accept();
//do cleanup here
serverSocket.close();
} catch (Exception e) {
}
System.exit(0);
}
}.start();
You can use this one: exit()
It's possible to predefine all the action before virtual machine is totally stoppeed thus you can save your data and performa all actions to prevent the data loss.
I'm not sure it's a good way, because I've just started Java study, but it seems working.