Bash script subprocess locking Java app/console - java

I have the following simple script (test.sh):
#!/bin/bash
tail -f /var/log/dmesg > /tmp/output.log &
echo "THE END"
exit 0
After calling this test.sh script from a java program (remotely under ssh), the java console (eclipse) stay locked. Then,
1) If I manually kill the "tail -f /var/log/dmesg > /tmp/output.log" process in the server, the console unlocks and I get the "THE END" message in the console.
2) If I remove the "tail -f /var/log/dmesg > /tmp/output.log" from the script and run the java app, no lock happens and I get the "THE END" message in the console.
Is there anyone to run tail -f in bg through test.sh, and continue with the java app flow?

Try with nohup:
nohup tail -f /var/log/dmesg > /tmp/output.log &
SSH will sometimes wait for all processes to close the tty before exiting. nohup will set stdin to /dev/null and stdout/stderr to a file, so SSH can exit immediately (flushing any buffers that may be keeping "THE END" from showing).

There may also be some pitfalls on the Java side when it comes to running Unix system commands via Java. For example, if the standard I/O streams (stdout, stderr, stdin) of Unix-based operating systems are not being read in Java Threads, Unix system calls may unexpectedly block or even deadlock (for more detailed information on this topic please see Java exec - execute system processes with Java ProcessBuilder and Process (part 3) (2012).
Try the following Java sample code based on ThreadedStreamHandler.java, SystemCommandExecutor.java and ProcessBuilderExample.java that runs commands.add("ssh localhost /tmp/test.sh"); (it worked for me using the latest Eclipse Java EE IDE for Web Developers - Mac OS X version):
# References:
#
# - "Java exec - execute system processes with Java ProcessBuilder and Process (part 3)" (2012),
# http://alvinalexander.com/java/java-exec-processbuilder-process-3
#
# - "Running system commands in Java applications" (2012),
# http://alvinalexander.com/java/edu/pj/pj010016
#
# - "When Runtime.exec() won't: Navigate yourself around pitfalls related to the Runtime.exec() method" (2000),
# http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html
mkdir -vp /tmp/com/devdaily/system
cd /tmp/com/devdaily/system
curl -LO http://alvinalexander.com/java/edu/java-exec/ProcessBuilderExample.java
curl -LO http://alvinalexander.com/java/edu/java-exec/SystemCommandExecutor.java
curl -LO http://alvinalexander.com/java/edu/java-exec/ThreadedStreamHandler.java
cd ../../..
# create commands.add("ssh localhost /tmp/test.sh");
printf '%s\n' 'H' ',s|ls -l.*tmp|ssh localhost /tmp/test.sh|' 'wq' |
ed -s com/devdaily/system/ProcessBuilderExample.java
echo '
#!/bin/bash
tail -f /private/var/log/system.log > /tmp/output.log &
echo "THE END"
exit 0
' > /tmp/test.sh
chmod +x /tmp/test.sh
javac com/devdaily/system/ProcessBuilderExample.java
java com/devdaily/system/ProcessBuilderExample
java -version
# java version "1.6.0_31"
# Java(TM) SE Runtime Environment (build 1.6.0_31-b04-415-10M3646)
# Java HotSpot(TM) 64-Bit Server VM (build 20.6-b01-415, mixed mode)
# Eclipse Java EE IDE for Web Developers (Mac OS X version).
# Version: Juno Service Release 2
# Build id: 20130225-0426
#
# use the following menu sequences:
# Window --> Show View --> Console
# Run --> External Tools --> External Tools Configuration... --> Program (double-click) --> New_configuration
# Location: /usr/bin/java
# Working Directory: /tmp
# Arguments: com/devdaily/system/ProcessBuilderExample

Have a look at htis article, it describes main mistakes while working with processes. What you have to do is to add a Steam Gobbler - consumer of input streams, so that outer progrem not to stuck while writing to output, becouse of full buffer.

Related

Empty Tomcat thread dumps using jstack

Trying to collect thread dump of Apache Tomcat8.5 in windows server I ended using jstack with psexec as follows(as using jstack directly wasn't possible, so I'm using pexec to execute jstack using syetm process):
PsExec.exe -s "C:\Program Files\Java\jdk1.7.0_40\bin\jstack.exe" -l 5340 > dumps.txt
with 5340 is the PID of the running Tomcat8 process.
The execution started without any errors and it shows this output:
PsExec.exe -s "C:\Program Files\Java\jdk1.7.0_40\bin\jstack.exe" -l 5340 > dumps.txt
PsExec v2.2 - Execute processes remotely Copyright (C) 2001-2016 Mark Russinovich Sysinternals - www.sysinternals.com
Starting C:\Program Files\Java\jdk1.7.0_40\bin\jstack.exe on VMNAME...
When I check th dumps.txt I find it empty, even I'm running The command line as Admin.
Thnks for your help!
As a conclusion to the discussion. You need to use the same VM version for executing a jstack command as the VM version you are going to inspect. In case of any errors, you could try a -F param to jstack.
Also, you don't need PsExec tools on newer VMs anymore.

Unix script on startup in /etc/init.d not working

I've been trying to get my Java application to run as a daemon in the background after startup. I've followed the instructions given in the top answer here and to no avail.
This is my /etc/init.d/myapp file:
#!/bin/bash
# MyApp
#
# description: bla bla
case $1 in
start)
/bin/bash /var/lib/myapp/start.sh
;;
stop)
/bin/bash /var/lib/myapp/stop.sh
;;
restart)
/bin/bash /var/lib/myapp/stop.sh
/bin/bash /var/lib/myapp/start.sh
;;
esac
exit 0
as for the /var/lib/myapp/start.sh, it looks like this:
#!/bin/bash
java -jar myapp-1.0.0RC.jar &
and works fine when run from a terminal via ssh.
i also ran the update-rc.d myscript defaults command, and was only given a warning about headers and LSB
After this, once i reboot the server, the app isnt running. Any help is appreciated.
Thanks.
When bash scripts are run, they are not automatically ran from the same directory that contains them.
You will either need to update your scripts to change directory to that which holds the scripts before starting the jar:
#!/bin/bash
cd /var/lib/myapp/
java -jar myapp-1.0.0RC.jar &
Or, refer to the jar file with a full path:
#!/bin/bash
java -jar /var/lib/myapp/myapp-1.0.0RC.jar &
Check if your service is registered properly via chkconfig
$ chkconfig --list
If not you can see your service listed on the output, then try adding this lines to your script
#!/bin/bash
# chkconfig: 2345 95 20
# description: bla bla
# processname: myapp
and then run
chkconfig --add myapp
For more information you can check the man page for chkconfig

Run a Java Application as a Service on Linux

I have written a Java server application that runs on a standard virtual hosted Linux solution. The application runs all the time listening for socket connections and creating new handlers for them. It is a server side implementation to a client-server application.
The way I start it is by including it in the start up rc.local script of the server. However once started I do not know how to access it to stop it and if I want to install an update, so I have to restart the server in order to restart the application.
On a windows PC, for this type of application I might create a windows service and then I can stop and start it as I want. Is there anything like that on a Linux box so that if I start this application I can stop it and restart it without doing a complete restart of the server.
My application is called WebServer.exe. It is started on server startup by including it in my rc.local as such:
java -jar /var/www/vhosts/myweb.com/phpserv/WebServer.jar &
I am a bit of a noob at Linux so any example would be appreciated with any posts. However I do have SSH, and full FTP access to the box to install any updates as well as access to a Plesk panel.
I wrote another simple wrapper here:
#!/bin/sh
SERVICE_NAME=MyService
PATH_TO_JAR=/usr/local/MyProject/MyJar.jar
PID_PATH_NAME=/tmp/MyService-pid
case $1 in
start)
echo "Starting $SERVICE_NAME ..."
if [ ! -f $PID_PATH_NAME ]; then
nohup java -jar $PATH_TO_JAR /tmp 2>> /dev/null >> /dev/null &
echo $! > $PID_PATH_NAME
echo "$SERVICE_NAME started ..."
else
echo "$SERVICE_NAME is already running ..."
fi
;;
stop)
if [ -f $PID_PATH_NAME ]; then
PID=$(cat $PID_PATH_NAME);
echo "$SERVICE_NAME stoping ..."
kill $PID;
echo "$SERVICE_NAME stopped ..."
rm $PID_PATH_NAME
else
echo "$SERVICE_NAME is not running ..."
fi
;;
restart)
if [ -f $PID_PATH_NAME ]; then
PID=$(cat $PID_PATH_NAME);
echo "$SERVICE_NAME stopping ...";
kill $PID;
echo "$SERVICE_NAME stopped ...";
rm $PID_PATH_NAME
echo "$SERVICE_NAME starting ..."
nohup java -jar $PATH_TO_JAR /tmp 2>> /dev/null >> /dev/null &
echo $! > $PID_PATH_NAME
echo "$SERVICE_NAME started ..."
else
echo "$SERVICE_NAME is not running ..."
fi
;;
esac
You can follow a full tutorial for init.d here and for systemd (ubuntu 16+) here
If you need the output log replace the 2
nohup java -jar $PATH_TO_JAR /tmp 2>> /dev/null >> /dev/null &
lines for
nohup java -jar $PATH_TO_JAR >> myService.out 2>&1&
A simple solution is to create a script start.sh that runs Java through nohup and then stores the PID to a file:
nohup java -jar myapplication.jar > log.txt 2> errors.txt < /dev/null &
PID=$!
echo $PID > pid.txt
Then your stop script stop.sh would read the PID from the file and kill the application:
PID=$(cat pid.txt)
kill $PID
Of course I've left out some details, like checking whether the process exists and removing pid.txt if you're done.
Linux service init script are stored into /etc/init.d. You can copy and customize /etc/init.d/skeleton file, and then call
service [yourservice] start|stop|restart
see http://www.ralfebert.de/blog/java/debian_daemon/. Its for Debian (so, Ubuntu as well) but fit more distribution.
Maybe not the best dev-ops solution, but good for the general use of a server for a lan party or similar.
Use screen to run your server in and then detach before logging out, this will keep the process running, you can then re-attach at any point.
Workflow:
Start a screen: screen
Start your server: java -jar minecraft-server.jar
Detach by pressing: Ctl-a, d
Re-attach: screen -r
More info here: https://www.gnu.org/software/screen/manual/screen.html
Another alternative, which is also quite popular is the Java Service Wrapper. This is also quite popular around the OSS community.
Referring to Spring Boot application as a Service as well, I would go for the systemd version, since it's the easiest, least verbose, and best integrated into modern distros (and even the not-so-modern ones like CentOS 7.x).
The easiest way is to use supervisord. Please see full details here: http://supervisord.org/
More info:
https://askubuntu.com/questions/779830/running-an-executable-jar-file-when-the-system-starts/852485#852485
https://www.digitalocean.com/community/tutorials/how-to-install-and-manage-supervisor-on-ubuntu-and-debian-vps
Here is a sample shell script (make sure you replace the MATH name with the name of the your application):
#!/bin/bash
### BEGIN INIT INFO
# Provides: MATH
# Required-Start: $java
# Required-Stop: $java
# Short-Description: Start and stop MATH service.
# Description: -
# Date-Creation: -
# Date-Last-Modification: -
# Author: -
### END INIT INFO
# Variables
PGREP=/usr/bin/pgrep
JAVA=/usr/bin/java
ZERO=0
# Start the MATH
start() {
echo "Starting MATH..."
#Verify if the service is running
$PGREP -f MATH > /dev/null
VERIFIER=$?
if [ $ZERO = $VERIFIER ]
then
echo "The service is already running"
else
#Run the jar file MATH service
$JAVA -jar /opt/MATH/MATH.jar > /dev/null 2>&1 &
#sleep time before the service verification
sleep 10
#Verify if the service is running
$PGREP -f MATH > /dev/null
VERIFIER=$?
if [ $ZERO = $VERIFIER ]
then
echo "Service was successfully started"
else
echo "Failed to start service"
fi
fi
echo
}
# Stop the MATH
stop() {
echo "Stopping MATH..."
#Verify if the service is running
$PGREP -f MATH > /dev/null
VERIFIER=$?
if [ $ZERO = $VERIFIER ]
then
#Kill the pid of java with the service name
kill -9 $($PGREP -f MATH)
#Sleep time before the service verification
sleep 10
#Verify if the service is running
$PGREP -f MATH > /dev/null
VERIFIER=$?
if [ $ZERO = $VERIFIER ]
then
echo "Failed to stop service"
else
echo "Service was successfully stopped"
fi
else
echo "The service is already stopped"
fi
echo
}
# Verify the status of MATH
status() {
echo "Checking status of MATH..."
#Verify if the service is running
$PGREP -f MATH > /dev/null
VERIFIER=$?
if [ $ZERO = $VERIFIER ]
then
echo "Service is running"
else
echo "Service is stopped"
fi
echo
}
# Main logic
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status
;;
restart|reload)
stop
start
;;
*)
echo $"Usage: $0 {start|stop|status|restart|reload}"
exit 1
esac
exit 0
From Spring Boot application as a Service, I can recommend the Python-based supervisord application. See that stack overflow question for more information. It's really straightforward to set up.
Other answers do a good job giving custom scripts and setups depending on your platform. In addition to those, here are the mature, special purpose programs that I know of:
JSW from TanukiSoftware
YAJSW is an open source clone from the above. It is written in Java, and it is a nanny process that manages the child process (your code) according to configurations. Works on windows / linux.
JSVC is a native application. Its also a nanny process, but it invokes your child application through the JNI, rather than as a subprocess.
You can use Thrift server or JMX to communicate with your Java service.
From Spring Boot Reference Guide
Installation as an init.d service (System V)
Simply symlink the jar to init.d to support the standard start, stop, restart and status commands.
Assuming that you have a Spring Boot application installed in /var/myapp, to install a Spring Boot application as an init.d service simply create a symlink:
$ sudo ln -s /var/myapp/myapp.jar /etc/init.d/myapp
Once installed, you can start and stop the service in the usual way. For example, on a Debian based system:
$ service myapp start
If your application fails to start, check the log file written to /var/log/<appname>.log for errors.
Continue reading to know how to secure a deployed service.
After doing as written I've discovered that my service fails to start with this error message in logs: start-stop-daemon: unrecognized option --no-close. And I've managed to fix it by creating a config file /var/myapp/myapp.conf with the following content
USE_START_STOP_DAEMON=false
It is possible to run the war as a Linux service, and you may want to force in your pom.xml file before packaging, as some distros may not recognize in auto mode. To do it, add the following property inside of spring-boot-maven-plugin plugin.
<embeddedLaunchScriptProperties>
<mode>service</mode>
</embeddedLaunchScriptProperties>
Next, setup your init.d with:
ln -s myapp.war /etc/init.d/myapp
and you will be able to run
service myapp start|stop|restart
There are many other options that you can find in Spring Boot documentation, including Windows service.
Im having Netty java application and I want to run it as a service with systemd. Unfortunately application stops no matter of what Type I'm using. At the end I've wrapped java start in screen. Here are the config files:
service
[Unit]
Description=Netty service
After=network.target
[Service]
User=user
Type=forking
WorkingDirectory=/home/user/app
ExecStart=/home/user/app/start.sh
TimeoutStopSec=10
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
start
#!/bin/sh
/usr/bin/screen -L -dmS netty_app java -cp app.jar classPath
from that point you can use systemctl [start|stop|status] service.
To run Java code as daemon (service) you can write JNI based stub.
http://jnicookbook.owsiak.org/recipe-no-022/
for a sample code that is based on JNI. In this case you daemonize the code that was started as Java and main loop is executed in C. But it is also possible to put main, daemon's, service loop inside Java.
https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo029
Have fun with JNI!
However once started I don't know how to access it to stop it
You can write a simple stop script that greps for your java process, extracts the PID and calls kill on it. It's not fancy, but it's straight forward.
Something like that may be of help as a start:
#!/bin/bash
PID = ps ax | grep "name of your app" | cut -d ' ' -f 1
kill $PID

jstack: Target process not responding

I am running Ubuntu server edition and I wanted to take a thread dump of Tomcat.
So, I first tried to find out which PID tomcat uses:
$ jps -l
5809 sun.tools.jps.Jps
But it's not there?
So, I used top instead and found out the PID 5730.
Then I called jstack to get the thread dump:
$ sudo jstack -l 5730
5730: Unable to open socket file: target process not responding or HotSpot VM not loaded
The -F option can be used when the target process is not responding
What's going on? :-(
I already tried to export CATALINA_TMPDIR as described in Jstack and Jstat stopped working with upgrade to JDK6u23 but that didn't change anything:
$ export CATALINA_TMPDIR=/tmp
$ sudo /etc/init.d/tomcat6 restart
* Stopping Tomcat servlet engine tomcat6
...done.
* Starting Tomcat servlet engine tomcat6
...done.
$ sudo jstack -l 5934 // new PID after restart
5934: Unable to open socket file: target process not responding or HotSpot VM not loaded
The -F option can be used when the target process is not responding
Update:
I also tried sudo -u tomcat6 jstack -l -F 5730 > threaddumpexceptions2.txt but it only gives me tons of exceptions on the console.
I got it working by doing two things:
Changed call to: sudo -u tomcat6 jstack -J-d64 -m pid
Replaced OpenJDK with Sun's original sun-6-jdk and sun-6-jre packages
Explanation for part 1: I switched to 64-bit mode, used sudo and run the command as Tomcat user.
Note: Part 2 might not be necessary. For some users it seems like part 1 is enough. In fact, try to add just the sudo command first. It might already do the trick.
I think you need to run jstack as the same user that runs the Tomcat process. Note also that jps only returns processes for the current user. You would get the pid for the Tomcat process by running jps with sudo or as the Tomcat process user.
This bug report may also be useful: https://bugs.launchpad.net/ubuntu/+source/sun-java6/+bug/597098
#Valmar, I find the same topic post here.
Unable to get thread dump? Any ideas why my app blocks?
It seems the workaround is sudo -u tomcat6 kill -3 <pid>.
Try to switch to process user and then use jstack:
sudo -u {process user} jstack > dump
This also worked for me:
sudo -u tomcat6 kill -3 pid
It looks like nothing happens but when you look in the logs the stacks are there. They look like exceptions if your not expecting them.
I find it useful to use something like 'ps -eo pid,user,command | grep java' to find the actual java command being used, then use the directory to find the matching jstack etc.
# ps -eo user,command | grep '[j]ava' | cut -d' ' -f1
someuser /usr/lib/jvm/java/bin/java
# /usr/lib/jvm/java/bin/java -version
java version "1.6.0_45"
Java(TM) SE Runtime Environment (build 1.6.0_45-b06)
Java HotSpot(TM) 64-Bit Server VM (build 20.45-b01, mixed mode)
So its 64-bit, running as 'someuser'. su to that user and run run jstack etc. from that same directory. (ie. /usr/lib/jvm/java/bin/jstack
Useful when you're on a server with various different installations / implementations of Java.
For Tomcat users having this issue, check your catalina.out log file.
I was having the same problems "22693: Unable to open socket file: target process not responding or HotSpot VM not loaded". I gave up and was trying to find anything about what happened before it locked up, but then there was the jstack output in the log file.
I had same problem, but none of below solution worked for me:
jstack <pid>
jstack -J-d64 -m <pid>
sudo -u <user> jstack ...
I finally upgraded JDK from jdk1.6.0_24 to jdk1.7.0_67 and every things worked.
For those finding this answer six years after it was asked and they are on CentOS 7 note that SELinux will stop jmap from writing the heap dumps as, out of the box, it will deny writing to a socket unless the directory has the type tomcat_tmp_t.
In my case, I write my heap dumps under /usr/share/tomcat/.jmap. This directory is owned by my runtime user.
Therefore to allow jmap to write to this directory:
semanage fcontext -a -t tomcat_tmp_t "/usr/share/tomcat/.jmap(/.*)?"
restorecon /usr/share/tomcat -vR
Which allows us to then run, as our tomcat user:
jmap -dump:format=b,file=/usr/share/tomcat/.jmap/tomcat-`date +%s`.bin <pid>
My problem was, I ran the process by the terminal. Then for testing Its jstack, I paused the process by ctrl+z. The process was not able to respond. To solve this problem, I resumed the process by fg and checked its jstack by another terminal.

How do I detect 64-bit Java from the command line?

Is there any way to get at Java internal properties, such as sun.arch.data.model , from a command line on windows? I need a command to put in a batch script that will detect the java architecture type: 32-bit or 64-bit .
If you are using Sun's VM (and I would suppose other VMs have similar details in their version information), you can check for the string "64-Bit" in the output of "java -version":
java -version 2>&1 | find "64-Bit" >nul:
if errorlevel 1 (
echo 32-Bit
) else (
echo 64-Bit
)
jarnbjo's script is for Windows. In Unix shell, you can use the following script.
#!/bin/sh
BIT=`java -version 2>&1`
case "$BIT" in
*64-Bit*)
echo "64-Bit"
;;
*)
echo "32-Bit"
;;
esac
Here is a prewritten property dump program for you: linky
If you install Groovy you can use
groovy -e "System.properties.each{println it}"
for all properties, and
groovy -e "println System.properties['sun.arch.data.model']"
for specific properties.
Installing Groovy is as easy as extracting a zip and add to path.

Categories