4

I execute some commands using SSHJ, I do it using this method:

  private Command executeCommand(String command, SSHClient client) {
    Command commandObject = client.startSession().exec(command);
    commandObject.join();
    return commandObject;
  }

It works well until I execute this command:

cd $SOLR; nohup java -Dsolr.solr.home=./solr -DSTOP.PORT=8079 -DSTOP.KEY=stopkey -jar start.jar 2> logs/solr.log &

In this case the whole program hangs on

commandObject.join();

Of course the process it starts is started. Also the same line executed from shell returns right away.

Any idea why and how to overcome this?

EDIT: the same happens when I don't join() but read the sysout of the command (with commons-io):

IOUtils.toString(commandObject.getInputStream()))
ilfrin
  • 261
  • 3
  • 10
  • One idea would be to redirect stdin and stderr, so placing a `2>&1` before the last ampersand may be of help. Though, I'm having a similar issue with a different command, so it probably won't completely solve it. – bstempi Jan 23 '14 at 20:02
  • Correction to my comment: it's unhelpful -- nohup will redirect for you if you don't specify otherwise. I've noticed that there are some threading issues in this lib; perhaps you've encountered one? – bstempi Jan 24 '14 at 17:54
  • @ilfrin , The main thread blocks because you are calling `commandObject.join()` without a timeout. This blocks the current thread to wait for a notification. If the called program hangs, the main thread hangs as well. – Boyan Feb 16 '16 at 14:20

2 Answers2

2

Presumably the java app you're running is a daemon? (or at least, it waits a long time before exiting)

It may be better to have a dedicated script on your target machine that controls the initialisation/shutdown of the daemon rather than relying on SSH clients to send the correct sequence of commands. This way, the script encapsulates all the things needed to cleanly start and stop your daemon and other apps that need to control it simply call this script to start and stop without needing to know details about where to log, the java command needed to start it, how to background the process, etc.

You can either roll your own init-style script or use Tanuki's Java Service Wrapper (or similar) for this.

Jonny
  • 842
  • 5
  • 14
1

I have had the same issue.

My personal recommendation is that whenever you use join you should actually set some timeout for it to expire and don't lock the thread forever. In my case for using multiple commands I initialize a Shell instance, and, for instance would do something like this:

try
{
            shell = session.startShell();
}
catch (Exception e)
{
            // failed to open
            return;
}
outputStream = shell.getOutputStream();
outputStream.write(Strings.toUTF8ByteArray("some fast command\n"));
outputStream.flush();
try {   shell.join(1, TimeUnit.SECONDS); }
catch (Exception e) {}
outputStream.write(Strings.toUTF8ByteArray("some complex command\n"));
outputStream.flush();
try {   shell.join(30, TimeUnit.SECONDS); }
catch (Exception e) {}

Hope it may be useful for anybody having some similar problem.