I have a java server application running on jboss. I want to kill the jboss process once there is any exception in starting the application (specifically bean initialization). I want to make sure that if there is any exception in connecting to the DB(the bean), both application and jboss process should be killed. I tried System.exit(1), but it didn't help.
Solved !!
Thanks #daveb.
I tried your solution. It worked!. But calling an external script looked a little weird to me. I was able to kill JBOSS process using System.exit(1) itself.
The key point is that System.exit(1) should be called from a new thread. Something like this.
Thread thread = new Thread(){
public void run(){
try {
System.exit(1);
} catch (Exception e) {
log.error("Exception while calling System.exit(1) {}",e);
}
}
};
thread.start();
you can put your kill command in a shell script and invoke it from your java bean using ProcessBuilder...here's an example...
String shutdownScript = "/etc/jboss-as/shutdown.sh";
try {
log.info("Executing shutdown script: {0}", shutdownScript);
String[] command = {"/bin/bash", shutdownScript};
ProcessBuilder p = new ProcessBuilder(command);
Process p2 = p.start();
BufferedReader br = new BufferedReader(new InputStreamReader(p2.getInputStream()));
String line;
log.info("Output of running " + command + " is: ");
while ((line = br.readLine()) != null) {
log.info(line);
}
} catch (Exception e) {
log.error("Unable to execute instance shutdown script: "+ExceptionUtils.getFullStackTrace(e));
}
A cleaner solution (if you are using JavaEE) would be to create a #Startup bean and run some database checks, if the DB connection is down you can throw a throw a StartException which will automatically undeploy the app for you eg....
throw new StartException("Could not initialise DB connection");
Related
I'm having trouble with ProcessBuilder not running a command on the server.
Early in my project I use Runtime.exec() just to retrieve output from a program which works fine:
private List<SatelliteCode> getSatelliteCodes() {
List<SatelliteCode> codes = new ArrayList<>();
Runtime runtime = Runtime.getRuntime();
String[] commands = { "w_scan", "-s?" };
Process process;
try {
process = runtime.exec(commands);
BufferedReader error = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String s = error.readLine(); // discard first line
while ((s = error.readLine()) != null) {
s = s.trim();
int i = s.indexOf('\t'); // separated by a tab!?!?
codes.add(new SatelliteCode(s.substring(0, i), s.substring(i)));
}
} catch (IOException e) {
e.printStackTrace();
}
return codes;
}
Running this in the terminal works fine and I get all the output I need:
w_scan -fs -cGB -sS19E2 > channels.conf
However, the server needs to grab the ongoing output from the 'process.getErrorStream()' to display in the web interface. What is actually happening is the ProcessBuilder is failing and returning an exit code of 1.
The function that initialises the ProcessBuilder and to start the scan running is [EDIT 1]:
private static StringBuilder scan_error_output = null;
#Override
public boolean startSatelliteScan(String user, String country_code, String satellite_code) {
UserAccountPermissions perm = validateUserEdit(user);
if (perm == null) return false;
Shared.writeUserLog(user, Shared.getTimeStamp() +
": DVB satellite scan started " +
country_code + " - " + satellite_code +
System.lineSeparator() + System.lineSeparator());
scan_error_output = new StringBuilder();
new ScanThread(country_code, satellite_code).start();
// write out country code and satellite code to prefs file
BufferedWriter bw = null;
try {
bw = new BufferedWriter(new FileWriter(satellite_last_scan_codes));
bw.write(country_code); bw.newLine();
bw.write(satellite_code); bw.newLine();
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
That will then run two other threads on the server, one that will run the scan itself and wait for it to finish so that it can get the final scan data. And the other which constantly updates the output from the std error stream which is then polled at intervals from the clients browser. This is much like showing the ongoing output from the terminal.
The scan thread (which fails to start the process) [EDIT 1]:
private static class ScanThread extends Thread {
private String cc, sc;
public ScanThread(String country_code, String satellite_code) {
cc = country_code;
sc = satellite_code;
}
public void run() {
ProcessBuilder pb = new ProcessBuilder("/usr/bin/w_scan",
"-fs", "-c" + cc, "-s" + sc);
pb.redirectOutput(new File(satellite_scan_file));
Process process;
try {
System.out.println("Scan thread started");
process = pb.start();
IOScanErrorOutputHandler error_output_handler = new IOScanErrorOutputHandler(process.getErrorStream());
error_output_handler.start();
int result = process.waitFor();
System.out.println(cc + " - " + sc + " - " +
"Process.waitFor() result " + result);
} catch (IOException e) {
System.out.println(e.getMessage());
e.printStackTrace();
} catch (InterruptedException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
System.out.println("Scan thread finished");
}
}
The error output stream thread which captures the output which obviously doesn't start due to the scan thread failing:
private static class IOScanErrorOutputHandler extends Thread {
private InputStream inputStream;
IOScanErrorOutputHandler(InputStream inputStream) {
this.inputStream = inputStream;
}
public void run() {
Scanner br = null;
try {
System.out.println("Scan thread Error IO capture running");
br = new Scanner(new InputStreamReader(inputStream));
String line = null;
while (br.hasNextLine()) {
line = br.nextLine();
scan_error_output.append(line + System.getProperty("line.separator"));
}
} finally {
br.close();
}
System.out.println("Scan thread Error IO capture finished");
scan_error_output = null;
}
}
And the server function which returns the std error output progress:
#Override
public String pollScanResult(String user) {
if (validateUserEdit(user) == null) return null;
StringBuilder sb = scan_error_output; // grab instance
if (sb == null) return null;
return sb.toString();
}
As mentioned above, Runtime.exec() works fine, but the ProcessBuilder is failing.
NB: I'm on Linux Mint 18.1, using Apache Tomcat 8 as the server, linux default JDK 8 and GWT 2.7 [Correction from 2.8] in Eclipse Neon.
Can anyone see what I am doing wrong?
Many thanks in advance...
[EDIT 1]
Whilst developing this on another machine, Linux Mint 17.2, JDK 8 and Apache Tomcat 7, for DVB-T, this method worked fine and polling for the scan output showed up in the client's browser.
The ProcessBuilder.start still returns 1 and an empty file is created for the output scan file.
[EDIT 2]
It appears that the reason the ProcessBuilder is failing is because the user 'tomcat8' doesn't have permissions to run 'w_scan'. 'w_scan' works from the terminal, but not from the tomcat server. Somehow I've got to fix that now.
[SOLUTIONS]
After being put in the right direction by VGR for getting the error stream from the ProcessBuilder, I started digging further and found I was getting:
main:3909: FATAL: failed to open '/dev/dvb/adapter0/frontend0': 13 Permission denied
Apache tomcat 8 didn't have permission to access the DVB-S frontend to run a scan. This was fixed in two ways:
1 - 03catalina.policy I added the extra permissions (whether they made a difference I do not know).
grant codeBase "file:/dev/dvb/-" {
permission java.io.FilePermission "file:/dev/dvb/-", "read, write";
permission java.security.AllPermission;
};
2 - The dvb frontends belong to the 'video' group. So I needed to add the user tomcat8 to that group.
usermod -a -G video tomcat8
All works for now...
You are not doing the same thing with ProcessBuilder that you’re doing with Runtime.exec, so I don't know why you think ProcessBuilder is the problem.
You have a few problems with how you’re writing the command’s output to a file.
First, the presence of ">", satellite_scan_temp_file in your ProcessBuilder command is incorrect. Output redirection is not part of any command; it is handled by a shell. But when you run with Runtime.exec or ProcessBuilder, you are not running in a shell, you are executing the process directly. Neither w_scan nor any other command considers > a special character.
The correct way to redirect to a file is with the redirectOutput method:
ProcessBuilder pb = new ProcessBuilder(
"/usr/bin/w_scan", "-fs", "-s" + satellite_code, "-c" + country_code);
pb.redirectOutput(new File(satellite_scan_temp_file));
Second, your ScanThread code is ignoring the (currently incorrect) redirect, and is attempting to read the command’s output. But there is no output, because you are redirecting it all to a file.
Once you are properly redirecting output to a file, you can remove your BufferedReader and BufferedWriter loops completely.
Finally, it is worth noting that the error output you captured probably told you that > is not a valid argument to the w_scan process.
I am trying to execute it via:
Process process = Runtime.getRuntime().exec(spark_cmd);
with no luck. The command ran via shell starts my application which succeeds. Running it via exec start a process which dies shortly after and does nothing.
When I try
process.waitFor();
it hangs and waits forever. Real magic begins when I try to read something from the process:
InputStreamReader isr = new InputStreamReader(process.getErrorStream());
BufferedReader br = new BufferedReader(isr);
To do so I start a thread that reads from the stream in a while loop:
class ReadingThread extends Thread {
BufferedReader reader;
Wontekk(BufferedReader reader) {
this.reader = reader;
}
#Override
public void run() {
String line;
try {
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Application starts, does some stuff, and hangs. When I abort my application, spark application wakes up (??????????) and completes remaining work. Does anyone have reasonable explanation of what is happening?
thanks
You can send spark job as spark-submit with the help of java code with the help of SparkLauncher so you can go though below link and check it our
https://spark.apache.org/docs/1.4.0/api/java/org/apache/spark/launcher/SparkLauncher.html
One way is Spark launcher as told by #Sandeep Purohit
I'd offer shell script approach with nohup command to submit job like this...
This worked for me incase of mapreduce executions... same way you can
try for spark background jobs as well.
Have a look https://en.wikipedia.org/wiki/Nohup
"nohup spark-submit <parameters> 2>&1 < /dev/null &"
When ever, you get messages then you can poll that event and call this shell script. Below is the code snippet to do this...
/**
* This method is to spark submit
* <pre> You can call spark-submit or mapreduce job on the fly like this.. by calling shell script... </pre>
* #param commandToExecute String
*/
public static Boolean executeCommand(final String commandToExecute) {
try {
final Runtime rt = Runtime.getRuntime();
// LOG.info("process command -- " + commandToExecute);
final String[] arr = { "/bin/sh", "-c", commandToExecute};
final Process proc = rt.exec(arr);
// LOG.info("process started ");
final int exitVal = proc.waitFor();
LOG.trace(" commandToExecute exited with code: " + exitVal);
proc.destroy();
} catch (final Exception e) {
LOG.error("Exception occurred while Launching process : " + e.getMessage());
return Boolean.FALSE;
}
return Boolean.TRUE;
}
Moreover to debug
ps -aef | grep "your pid or process name"
Below command will list the open files opened by the process..
lsof -p <your process id >
Also, have a look at process.waitFor() never returns
my very first post here after long time of searching but yet get an answer regarding this issue, please help me in this issue.
I am using Netbean 6.9.1 to build a Java application which massive call to few different external program, therefore I used process and runtime function to call for external program.
The whole application process is separated into few stages and I wish to inform the user till which stage the application is currently running by updating the GUI textarea, the code is showed as below:
public void executeCommand (String cmd, File path)
{
try
{
****areaOutput.setText("Executing audio decoding, please wait till process is done\n");****
btnTranscribe.setEnabled(false);
areaOutput.setEditable(false);
areaOutput.setEnabled(false);
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(cmd , null, path);
InputStream stderr = proc.getErrorStream();
InputStreamReader isr = new InputStreamReader(stderr);
BufferedReader br = new BufferedReader(isr);
String line = null;
System.out.println("<ERROR>");
while ( (line = br.readLine()) != null)
System.out.println(line);
System.out.println("</ERROR>");
int exitVal = proc.waitFor();
System.out.println("Process exitValue: " + exitVal);
areaOutput.append("\n\nConversion is done, processing with features extraction....");
} catch (Throwable t)
{
t.printStackTrace();
}
}
As showed in the code above, I wish to set the Textarea and disable some button before executing the command, but when the application ran, all of these line seems unable to work and nothing is changed at the application itself till the command is finish executed, any solution to run the pre-command code execute first before the .exec() start to run?
I appreciate your great help and advice regarding this issue.
Best regards,
Striky
P/S:
hi there, I have make a Thread class for this CmdExec in order to execute cmd in different thread:
public class CmdExec extends Thread
{
private String cmd;
private File path;
public CmdExec() {
}
public CmdExec(String cmd, File path) {
this.cmd = cmd;
this.path = path;
}
public void run(){
try
{
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(cmd , null, path);
InputStream stderr = proc.getErrorStream();
InputStreamReader isr = new InputStreamReader(stderr);
BufferedReader br = new BufferedReader(isr);
String line = null;
System.out.println("<ERROR>");
while ( (line = br.readLine()) != null)
System.out.println(line);
System.out.println("</ERROR>");
int exitVal = proc.waitFor();
System.out.println("Process exitValue: " + exitVal);
} catch (Throwable t)
{
t.printStackTrace();
}
}
}
and in order to call to this class,
CmdExec tryDemo = new CmdExec();
tryDemo = new CmdExec(strSegment, fSegment);
tryDemo.run();
is used to start the thread, but I failed to put SwingUtilities.invokeLater in any part of these process, it simply won't run the tryDemo.run() because it is void...
Also, may I know so far am I doing right?? Very thank you for your kind help regarding this issue
P/S 2: I have just added another runnable code (so threads for process executing, runnable to GUI update) for GUI update command as below:
Runnable doWorkRunnable = new Runnable() {
public void run() {
System.out.println("hello world");
btnTranscribe.setEnabled(false);
areaOutput.setEditable(false);
areaOutput.setEnabled(false);
areaOutput.setText("Performing segmentation, please wait till process is done\n"); }
};
and I used SwingUtilies.invokeLater before the execution of process as below:
SwingUtilities.invokeLater(doWorkRunnable);
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(cmd , null, path);
But all these failed, am I get the wrong sequence for the GUI and process thread coordination?
you are executing this work on the EDT (the thread which updates the gui). so, the gui cannot update until all this work finishes. what you want to do is run a separate thread which does all the work and periodically calls SwingUtilities.invokeLater with a status update.
Try to put sleep before execute method. To verify what is happening.
Im trying to get console output from an external application in my application. When i call the externall app from my code it hangs with the message:
Configuring logging...
Configuring log4j from: C:\GPAT\log4j.cfg
and nothing happens. I searched through internet and it seems that it might be thread issue. But i cant modify this external application and i must go through log4j. I read the external app like this:
StringBuffer output = new StringBuffer();
try {
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(GSATCommand);
BufferedReader input = new BufferedReader(new InputStreamReader(proc.getInputStream()));
System.out.println("Test running...");
String line = null;
while ((line = input.readLine()) != null) {
System.out.println(line); // Writes the test output to console
output.append(line); output.append("\n");
}
int exitVal = proc.waitFor();
System.out.println("Process exitValue: " + exitVal);
System.out.println("Test successfully executed");
} catch (Throwable t) {
t.printStackTrace();
}
Thanks for reading.
You need to consume both stdout and stderr from a spawned process in separate threads, to prevent blocking behaviour (your spawned process will write to buffers, and block if those buffers aren't being emptied by your consuming process).
See the 2nd paragraph of this answer for more details and a link to a suitable fix.
I'm getting hundreds of these process_reaper threads that build up over time in my application. Anyone have any idea what these may be? They seem to be in my use of Runtime.exec() however I'm destroying my process in a finally statement but they still show up
screen shot:
http://www.dropmocks.com/mBxM5
Process proc = null;
String line;
try {
logger.info("Trying to execute command " + Arrays.asList(command).toString().replace(",", ""));
proc = Runtime.getRuntime().exec(command);
} catch (IOException e) {
logger.info("IOException while trying to execute " + command);
return false;
} finally {
if(proc != null) {
proc.destroy();
}
}
I haven't seen this one myself so I searched a little; it seems a process reaper is related to the Linux kernel process management and is a daemon thread. It maintains the process state so that resources can be freed/released/collected on process termination and so on. This resource might help you. There is a mention on reapers in the final parts.
you must call process.waitFor() after exec and before destory (asy action)