I am trying to write a shell script that records the exit status of a Java program. The script should simple launch a Java app, and if the Java app doesn't run for some reason, the shell script should detect this and take mitigating measures.
The following is my script:
#!/bin/bash
APPNAME="app"
APPFOLDER=$APPNAME
BACKUP=$APPFOLDER"-backup"
LOGFOLDER=$APPNAME"-log"
echo "Starting new app"
java -jar $APPFOLDER/$APPNAME*.jar > $LOGFOLDER/$APPNAME"_$(date+%Y.%m.%d.%s).log"
wait
STATUS=$?
if [ $STATUS -eq 0 ]
then
echo "Deployment successful" $?
else
echo "Deployment failed: ... derp" $?
fi
I have written a simple Swing GUI that runs fine. However, I packaged it as a jar without specifying an entry point. Hence, I should get the error:
Exception in thread "main" java.lang.NoClassDefFoundError: Demo$1
and the script should detect that the application failed to start.
All of this works FINE until I try to launch the Java app in the background using &. Whenever I do this:
java -jar $APPFOLDER/$APPNAME*.jar > $LOGFOLDER/$APPNAME"_$(date+%Y.%m.%d.%s).log" &
the script always returns a 0 for $?, indicating it passed.
What am I doing wrong? Is there a better way to go about detecting if the app failed to launch?
Thanks!
Wait! you are recording the exit status of wait!
This is why you see unexpected result with your script. Look at the man page for bash (wait is a bash built-in so you need to read the bash manual):
wait [-n] [n ...]
Wait for each specified child process and return its termination status. Each n may be a process ID... If n is not given, all currently active child processes are waited for, and the return status is zero(!). If n specifies a non-existent process or job, the return status is 127. Otherwise, the return status is the exit status of the last process ... waited for.
Since you have not specified the n (child pid to wait for) the return status is zero as per spec.
Another question is: do you really need a wait.
If you don't need to run your app in the background then just do this:
echo "Starting new app"
java -jar $APPFOLDER/$APPNAME*.jar > $LOGFOLDER/$APPNAME"_$(date+%Y.%m.%d.%s).log"
STATUS=$?
the only difference is that i removed unnecessary wait.
If for some reason you need to run your app in the background and read exit status later, then you need wait for that pid. To find out the pid of the last background process use special variable $!:
echo "Starting new app"
java -jar $APPFOLDER/$APPNAME*.jar > $LOGFOLDER/$APPNAME"_$(date+%Y.%m.%d.%s).log" &
CHILDPID=$!
wait "${CHILDPID}"
STATUS=$?
Here's short example of how it works:
user#s:~$ (sleep 10 && exit 42)&
[1] 27792
user#s:~$ wait "$!"
[1]+ Exit 42 ( sleep 10 && exit 42 )
user#s:~$ echo $?
42
What I want to know is if the app fails on startup or not. In the case of the former, my script would bag up the app and role out the previous version.
This purpose is too vague. Are you only interested in missing dependencies?
I don't think there is an easy way to distinguish between JRE non-zero exit code and you java application non-zero exit-code.
I can imagine lots of other reasons to unroll deployment many of which do not lead to non-zero exit code.
Related
What went wrong:
Execution failed for task ':run'.
> Process 'command 'home/comp/Downloads/jdk-13.0.2+8/bin/java'' finished with non-zero exit value 100
This has happened before and I tried updating Gradle and reinstalled java using a different method. Now the problem has come back. Any help appreciated.
Full build scan can be seen here:
https://scans.gradle.com/s/flb2fv7dwffnq
Encountered the same issue today with the same error message and code. In my case I had a shadowprocess running that occupied the port. Once I manage to shut that down I could run the process normally with no problems.
This error seam to indicate that the port is already in use and therefore you can't connect to the port.
Try checking if you have another program or process already occupying the port you wish to use. Also check that your build isn't already up and running cause having a second of the same build running will be blocked by the first as it was in my case with my shadow process.
Hope this help :)
I am working on a small app that should sign documents using digital signature and quit.
The signature can be in a PKCS#12 archive (.pfx file) or on a smartcard device.
Working with the pfx file is easy and working fine.
However, sometimes using the smartcard device, the process hangs on Windows 8 PCs.
The document is signed correctly, but the process doesn't terminate. It just hangs.
I'm using the Sun's PKCS#11 provider - sun.security.pkcs11.SunPKCS11
Basically I'm doing this:
SunPKCS11 provider = new SunPKCS11(configuration);
Security.addProvider(provider);
..... some work .....
provider.logout()
Security.removeProvider(provider);
Now... even if I call System.exit(0) or throw an exception at the end of the main method, I can see the stacktrace in the output but the process doesn't terminate.
I've added a shutdown hook to see if it is executed and it is, i.e. the JVM is trying to stop.
The hang occures rarely, only on Windows 8 PCs. Tried with different smartcards and it happens only with cards that use cmp11.dll (dlls are provided from the vendors of the smartcards).
Using the same dll for communication with the smartcard, however, works fine on Windows 7, XP or some Windows 8 PCs
Running it with Java 8, Update 45, on either x86 or x64 Windows 8
Tried to get a thread dump to see what is hanging:
public static void main(String[] args) {
// do my job, register provider, sign documents, remove provider ...
for(int i = 0; i < 20; ++i) {
System.err.println("Sleep... " + i);
Thread.sleep(2 * 1000);
}
System.err.println("Exiting...");
}
If I execute jstack -l 3232 > dump.log 2>&1 when Sleep... x is printing, everything looks OK.
However, if I execute jstack -F -l 3232 > dump2.log 2>&1 when Exiting... is printed and the app hangs (using -F because the process hangs), i got the following:
Attaching to process ID 3232, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.45-b02
Deadlock Detection:
No deadlocks found.
Thread Exception in thread "main"
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at sun.tools.jstack.JStack.runJStackTool(JStack.java:140)
at sun.tools.jstack.JStack.main(JStack.java:106)
Caused by: sun.jvm.hotspot.debugger.DebuggerException: Windbg Error: GetThreadIdBySystemId failed!
at sun.jvm.hotspot.debugger.windbg.WindbgDebuggerLocal.getThreadIdFromSysId0(Native Method)
at sun.jvm.hotspot.debugger.windbg.WindbgDebuggerLocal.getThreadIdFromSysId(WindbgDebuggerLocal.java:284)
at sun.jvm.hotspot.debugger.windbg.amd64.WindbgAMD64Thread.getThreadID(WindbgAMD64Thread.java:88)
at sun.jvm.hotspot.debugger.windbg.amd64.WindbgAMD64Thread.toString(WindbgAMD64Thread.java:81)
at java.lang.String.valueOf(String.java:2982)
at java.io.PrintStream.print(PrintStream.java:683)
at sun.jvm.hotspot.runtime.win32_amd64.Win32AMD64JavaThreadPDAccess.printThreadIDOn(Win32AMD64JavaThreadPDAccess.java:114)
at sun.jvm.hotspot.runtime.JavaThread.printThreadIDOn(JavaThread.java:265)
at sun.jvm.hotspot.tools.StackTrace.run(StackTrace.java:79)
at sun.jvm.hotspot.tools.StackTrace.run(StackTrace.java:45)
at sun.jvm.hotspot.tools.JStack.run(JStack.java:66)
at sun.jvm.hotspot.tools.Tool.startInternal(Tool.java:260)
at sun.jvm.hotspot.tools.Tool.start(Tool.java:223)
at sun.jvm.hotspot.tools.Tool.execute(Tool.java:118)
at sun.jvm.hotspot.tools.JStack.main(JStack.java:92)
... 6 more
I can see the process with PID 3232 in the task manager!
Any idea why it is not terminating or why jstack fails?
EDIT
Ok, tried to extract the signing in a separate process, execute it with Runtime.exec and then kill it with Process.destroy but... doesn't seem to help. The child process still stays in the task manager.
Aaaaand... now I have no other choice but to make it kill itself ;(
try {
String name = java.lang.management.ManagementFactory.getRuntimeMXBean().getName();
Runtime.getRuntime().exec("taskkill.exe /F /PID " + name.split("#")[0]);
}
catch(Throwable t) {
Runtime.getRuntime().exec("taskkill.exe /F /IM java.exe");
}
EDIT 2
Tried with Runtime.halt as well. Still doesn't terminate the process...
I would appreciate any ideas!
This won't address your root cause, but this method can be used to force the JVM to terminate:
http://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html#halt(int)
As the Javadoc says, use with extreme caution ;-)
I have some problem with sun.security.pkcs11.SunPKCS11 on Windows 8 PCs.This is working for me:
Runtime.getRuntime().exec("taskkill.exe /F /PID " + name.split("#")[0]);
Thread.sleep(500);
I am creating Processes using ProcessBuilder in my Java Application. The created process executes some FFMPEG commands which actually copy the RTSP streams in specified destination media file.
ProcessBuilder builder = new ProcessBuilder("ffmpeg", "-i", RTSP_URL, "-f", fileFormat, destFilePath);
Process processToExecute = builder.start();
I want to close the process before it completes its execution. So, If I run this FFMPEG command directly in windows CMD and then press 'CTRL+C' after 5 seconds then process get terminates with status '2'. And I can play the media file created so far.
So, If I do the same operation in my Java Application using:
process.destroy(); //I call this method after 5 sec
I get the status code '1' which means abnormal termination. I get the status by the following way:
processToExecute.destroy();
processToExecute.exitValue(); //This return me status '1'
And I can't play the media file and I think this is due to the abnormal termination of the process.
So how I can terminate the process created using ProcessBuilder in the same way we do in CMD with (CTRL+C) so that I may play the created media file ?
I want to terminate process (created using ProcessBuilder) in Java Application with status code of '2' that I get when I terminate process using CMD.
EDIT#01: --- Sharing Findings
So, when I try to delete that file once app terminates, I get the following error:
The Action Can't be Performed Because File is Opened in FFMPEG.exe
Which means that process is not terminating the command it is executing. That command still has occupied this file that's why I am not getting able to play it. Process gets terminate when I call:
processToExecute.destroy();
But, the task it is performing (that is execution of a command) is still active. Strange!!!!
EDIT#02: Sharing Ultimate Reason
Actually If I directly press 'CTRL+C' or 'q' in cmd when process is running then it terminates the process successfully and this process is no more visible in the currently executing processes lists.
And Programatically when I call method:
cmd> processToExecute.destroy();
It terminates the process but when I see the list of currently executing processes I can still see them over there.
And same scenario exists If I try to terminate this process using 'taskkill' or 'kill' command in another CMD by specifying their's name or pid that still process terminates abnormally.
P.S. I use the following command to see the running processes:
tasklist
So from this it proves that destroy() method from Application and 'taskkill or kill' command from another CMD is not terminating the process normally that pressing 'CTRL+C' and 'q' does.
Maybe try...
builder.inheritIO();
System.exit(2);
Or you could try to write to the stdin of the process...
process.getInputStream().write(exitCode);
I am trying to clear a batch file, which does some Weblogic Admin server data source update after which I need to restart the admin server..I am trying to automate the same through batch file...So I have;
call wlst UpdateDataSource.py
stopWebLogic.cmd weblogicUser weblogicPwd localhost:7001
startWebLogic.cmd
Now, how do I ensure that startWebLogic.cmd is executed only after the previous line has finished executing (i.e. after stopWebLogic.cmd finishes)
I'm assuming Windows, since you have .cmd files!?
You can use & between the scripts to run them in sequence. If you use && the ensuing scripts will only run if the previous ones completed successfully.
You can read more here.
Cheers,
I have a simple BASH script that wraps a java program with the intention of restarting it if that application crashes:
STOP=0
while [ "$STOP" -eq 0 ]
do
echo "Starting"
exec java com.site.app.Worker
echo "Crashed"
sleep 3
done
However if the Java process exits it also quits the bash script so the process is never started again.
E.g. (pointing at a fake class):
$ ./RestartApp.ksh
Starting
Exception in thread "main" java.lang.NoClassDefFoundError: com/site/app/Worker
Caused by: java.lang.ClassNotFoundException: com.site.app.Worker
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
Could not find the main class: com.site.app.Worker. Program will exit.
$
Is there a way I can catch the errors (but still display them) to allow the script to continue running?
Remove the exec. That's completely replacing the current process (your shell) with the Java VM.
Just remove that and it should work fine.
As Mat said, what exec does is to replace the current shell process by the Java process. It it fails, there is no-one waiting for it to relaunch it. exec can be a very useful and professional tool to use, but it is rather advanced.
An example of a right use for it would be a script that sets variables or priorities in the current shell, and then exec's the process you are wrapping.
The variable "STOP" does not seem to be used. I would simply go for:
while ! java com.site.app.Worker
do
echo Failed: Sleeping and restarting >&2
sleep 3
done