1

I have the below lines of code `

private String build(String command) {
        ShellExecutable obj = new ShellExecutable();
        String output = obj.executeCommand(command);
        return output;
    }

    private String executeCommand(String command) {
        StringBuffer output = new StringBuffer();
        Process p;
        String[] cmdarray = { "bash", "-c", command };
        try {
            System.out.println("Before Command Execution in Bash..& command is: " + command);
            p = Runtime.getRuntime().exec(cmdarray);
            System.out.println("After Command execution in Bash & Before waitFor..");
            p.waitFor();
            System.out.println("After wait for:  " + p.exitValue());
            System.out.println("After wait for:  " + p.isAlive());
            System.out.println("After Command execution in Bash..");
            if (p.getInputStream() != null) {
                System.out.println("Input Stream is present");
                BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
                String line = "";
                while ((line = reader.readLine()) != null) {
                    output.append(line + "\n");
                }
            }

            if (p.getErrorStream() != null) {
                System.out.println("Error Stream is present");
                BufferedReader errorReader = new BufferedReader(new InputStreamReader(p.getErrorStream()));
                String errorLine = "";
                while ((errorLine = errorReader.readLine()) != null) {
                    output.append(errorLine + "\n");
                }
            }
        } catch (Exception e) {
            System.out.println("Exception Occured:" + e.getLocalizedMessage() + "Message is:" + e.getMessage());
        }
        return output.toString();
    }

`

I am trying to run this as a foreground process in Linux, it works brilliant. But, when I try to run the same as a background process using nohup the service is stopping. I found similar kind of issues on stack overflow but I couldn't't figure out the solution for this particular case.

For the above code the output I am getting is as follows:

Called listApps...

Before Command Execution in Bash..& command is: xxxxxxxx

After Command execution in Bash & Before waitFor..

[1]+ Stopped nohup java -jar ReadingShell-0.0.1-SNAPSHOT-jar-with-dependencies.jar

I am not getting any exception in the above code, its just stopping without displaying anything. But, when I try displaying p.exitValue() before p.waitFor(), I printed the stacktrace, it is as follows,

java.lang.IllegalThreadStateException: process hasn't exited
at java.lang.UNIXProcess.exitValue(UNIXProcess.java:424)
at org.monitoring.ReadingShell.ShellExecutable.executeCommand(ShellExecutable.java:101)
at org.monitoring.ReadingShell.ShellExecutable.build(ShellExecutable.java:82)
at org.monitoring.ReadingShell.ShellExecutable.getApplicationList(ShellExecutable.java:46)
at spark.RouteImpl$1.handle(RouteImpl.java:72)
at spark.http.matching.Routes.execute(Routes.java:61)
at spark.http.matching.MatcherFilter.doFilter(MatcherFilter.java:130)
at spark.embeddedserver.jetty.JettyHandler.doHandle(JettyHandler.java:50)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1568)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
at org.eclipse.jetty.server.Server.handle(Server.java:564)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:317)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:251)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:279)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:110)
at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:124)
at org.eclipse.jetty.util.thread.Invocable.invokePreferred(Invocable.java:128)
at org.eclipse.jetty.util.thread.Invocable$InvocableExecutor.invoke(Invocable.java:222)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:294)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.produce(EatWhatYouKill.java:126)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:672)
at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:590)
at java.lang.Thread.run(Thread.java:745)
13
  • Print the value of p too, wrap the whole thing in a try catch and dump the exception Commented Aug 9, 2017 at 20:51
  • I tried that and the exception is: Exception Occured:process hasn't exit Commented Aug 9, 2017 at 20:58
  • Provide the stacktrace in your question Commented Aug 9, 2017 at 21:00
  • Marged, what do you mean by that? I provided you the exception I get when I try to access exit value of p without calling p.waitFor(); Commented Aug 9, 2017 at 21:33
  • An exception has a name and a stacktrace, what you provide is not complete. It would habe been worth mentioning the stacktrace and error from the beginning Commented Aug 9, 2017 at 21:36

3 Answers 3

2

You have to read the output streams before you wait for the end of the child process. Otherwise if the child writes more than a buffer's worth (512B? 4K?) to one of the streams, it will be made to wait until something reads and empties the buffer. But this won't happen since your parent process is already executing waitFor().

So, you have to create two threads to read these output streams, and start them before calling waitFor().

Sign up to request clarification or add additional context in comments.

1 Comment

I would say this is the real problem
1

By reading the opendjk source code for UnixProcess we see the following

public synchronized int waitFor() throws InterruptedException {
    while (!hasExited) {
        wait();
    }
    return exitcode;
}

public synchronized int exitValue() {
    if (!hasExited) {
        throw new IllegalThreadStateException("process hasn't exited");
    }
    return exitcode;
}

hasExited is never reset in the file so logically exitValue() cannot throw after waitFor() is called. (Unless it is interrupted)

Something must be different when you run it than in the code your question has. A minimal complete example class displaying the issue so we can reproduce it would help.

4 Comments

Nope, its the same code above. Remove all the print statements and run it in the foreground and then run it using nohup. It fails.
@Cheater Can you updater your question with a full class that reproduces the error with minmal code?
I am sorry, I can't update the entire class. But, the code I shared is related to the shell process. All you need to do is pass the shell commands to the build method.
@Cheater as you see from my code above it's not possible for exitValue() to throw an IllegalThreadStateException if you call waitFor() the line before. Something is missing from your question
0

I had a similar issue. The jar file would be fine if ran in the foreground, but stop when executed in nohup with the process/job going into Stopped.

Figured out that nohup will go into stopped if any of the inner scripts try to read from the terminal - see the post here

I used tmux to solve this as suggested by this thread

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.