On CentOS 7 i have /home/www/html/java-server/Objects/server.jar file which time to time crash for good reason and need to re-start again automatic so that its always running.
How to use forever like tool or any other similar for Java on CentOS?
For example on my NodeJS server i use as below.
forever start --minUptime 1000 --spinSleepTime 1000 SERVER.js
or
forever -m5 server.js
EDIT:
Reference: https://stackoverflow.com/a/28704296/285594
Wrap your jar in a shell script (this is optional but often useful) and use Supervisor to monitor it. Supervisor is highly customizable so you can set how many times your process can be restarted in a period of time, etc.
Here is how I did it.
I was trying to get a spring boot executable jar to run.
I created a bash script like the following
#!/bin/bash
forever start -c bash ./my-app.jar
The key here is to use "-c bash" otherwise forever failed to run the jar. Forever kept trying to run with node
You can write a class in Java that loops. It would call your application and catch exceptions, restarting the application after each exception. Make sure the wrapper class releases references to the application so that it can be GC'ed.
Related
I have a Java application run as a Windows service using procrun (specifically prunsrv). The service is defined as an exe StartMode so a batch file (run-my-app.bat) is run as the StartImage. Why I am not using jvm or java mode is a different story, not related to this issue (I was unable to run spring boot application with procrun, all examples did not work so I resorted to creating a batch file and calling java -jar my.jar). prunsrv.exe is actually renamed according to the application, say myapp.exe. The problem is that if myapp.exe is killed via the task manager, the java process remains! The batch file run-my-app.bat runs the application using the following line:
start "%APP_NAME%" /b "%JAVA_EXE%" -jar myapp.jar --spring.config.location=application.properties --logging.config=log4j2.xml
The batch file completes and the started Java process remains - I know this because if I print a message after the above "start" command I see the message in the log.
Is there any way to stop the java process when the prunsrv.exe (renamed myapp.exe) is killed?
Child processes will only be closed if they were created as Job objects.
IMHO it's not possible to tell prunsrv.exe to start processes as jobs, so the answer to your question is No.
You can of course terminate every single process individually. There are attempts to kill process trees, but be aware that Windows does not maintain parent-child-relationships. That means: If in a chain of 3 processes the middle one dies, the tree is not available any more.
I have a requirement where I need to develop application that reads TCP/IP Socket. I successfully made the program as Java program with No GUI means as soon as program runs it starts listening to the Socket and gets the response with the help of Netbeans IDE. Now as per my requirement i have to start execution of this program as soon as Linux system Booted.
Actually I am very novice in Java and Linux Platform, so have few doubts..
Is my Socket Program with no GUI is fine to be run as per my requirement.
How can I write script to run jar on Linux Boot up, I got to know. init.d is meant for this.
Ideally you should create a service wrapper for your java application and then make this service run on startup example here.
Use
sudo update-rc.d mytestserv defaults to run your service wrapper on startup on Ubuntu
So two things you'll need to do:
First create a small shell script to start your java program from a terminal. As you have packaged as a jar have a look at this, specifically the JAR Files as Applications section.
This may be sufficient: (although you'll want to use the full path to Java)
#!/bin/bash
java -jar path_to_jar_file
You should be able to run your script and successfully start your program.
Once you've got it starting from a script you can use standard linux tools to start the script. Either putting it in /etc/rc.local, or as you're using Ubuntu, use update-rc.d to start it on boot. See here for a very simple example of using update-rc.d
Hope this helps,
Will
I have some java code that is running continuously on a raspberry pi (from the terminal) and listening to a twitter stream and saving data to disk/usb.
I would like to know what would be the preferred method of detecting if a program is still running so I can take appropriate action and attempt to restart the app?
I hope that in this manner I could detect the program has failed, send an email to notify me and attempt to rerun the code. Would running this in a server environment be the best way to go?
Have a look at the forever project. If you have npm installed you can use that to install the forever package with the -g (for global install) parameter:
npm install forever -g
Then use the start argument to start the script. In your case this could be a bash file (.sh) with the required java commands.
forever start name-of-script-here
If the script would fail (system.exit in java or any fatal error) it will be restarted by forever. You can also get a list of all the running scripts managed by forever with:
forever list
In Unix let a parent process create the child java process and have it monitor. If it terminates then the parent can restart it.
The Unix fork returns the child pid to the parent.
Using this technique: Tracking the death of a child process parent can monitor child's death.
So I have the following problem: I have a web service running inside a Tomcat7 server on Linux. The web service however has to execute some commands (mostly file operations such as copy and mount). Copy I've replaced with java.nio, but I don't think that there is a replacement for mount.
So I'm trying to execute shell commands out of my Tomcat Java process. Unfortunately it doesn't execute my commands. I've implemented the execution of shell commands in Java before. So my code should be correct:
Process pr = Runtime.getRuntime().exec("mount -o loop -t iso9660 <myimage> <mymountpoint>");
pr.waitFor();
<myimage> and <mymountpoint> are absolute paths, so no issues there either.
I've debugged my commands and they are working when executed on the console.
I've tried sending other commands. Simple commands such as id and pwd are working!
I've tried using /bin/bash -c "<command>", which didn't work.
I've tried executing a shell script, which executes the command, which didn't work.
I've tried escaping the spaces in my command, which didn't work.
So I've digged even deeper and now I'm suspecting some Tomcat security policy (Sandbox?), which prevents me from executing the command. Since security is no issue for me (it's an internal system, completely isolated from the outside world), I've tried a hack, which became quite popular just recently:
System.setSecurityManager(null);
This didn't work either. I'm using Java7 and Tomcat7 on RHEL6. Tomcat7 is just extracted! I don't have any files in /etc/.. or any other folder than /opt/tomcat/, where I've extracted the zip from the Tomcat home page. I've searched the /opt/tomcat/conf folder for security settings, but all I could find was the file catalina.policy, where it didn't seem like I could set some security level for shell commands.
Any ideas?
A few things:
System.setSecurityManager(null);
you have just killed the security of your application.
Yes, Tomcat is running as root. If I execute id I'm root as well.
Fix this immediately!
Now on to the question. You shouldnt have Tomcat executing anything, you need to defer this to a separate process whether that be a shell script or another Java program. This should also remove what (I hope) was a dependency on root running Tomcat. It should be possible to perform this command as a non-privileged user that cannot log into the system normally. You would do this by configuring /etc/fstab and supplying that same user the permissions to do this. From a pure security POV the process that mounts should not be owned by the tomcat user. Nor should the tomcat user ever be root. So to recap:
1) Stop running Tomcat as root
2) Create a separate process outside of the context of Tomcat to run this mount
3) Create a tomcat user, this user should not be able to log into the system nor should it be a privileged user (admin,super user, etc)
4) Create a process user, this user should be configured exactly as the tomcat user
5) Edit /etc/fstab giving the process user the necessary permissions to mount correctly.
It's generally a bad idea to use the single-string form of Runtime.exec. A better option is to use ProcessBuilder, and split up the arguments yourself rather than relying on Java to split them for you (which it does very naïvely).
ProcessBuilder pb = new ProcessBuilder("/bin/mount", "-o", "loop", /*...*/);
pb.redirectErrorStream(true); // equivalent of 2>&1
Process p = pb.start();
You say you're on RHEL so do you have selinux active? Check your logs and see if this is what's blocking you (I think it's audit.log you're looking for, it's been a few years since I've used selinux). If this does turn out to be the problem then you should probably ask on superuser or serverfault rather than SO...
I'm not sure if that's the problem you are having, but I've seen issues when Runtime.exec() is used without reading the associated output buffers. You can find a detailed explanation and potential solutions here. Reading the output and error streams can also help you figure out what's going on at the OS level when you run the command.
I've recently had to do something like this from a Swing app.
You'll probably be able to pull it off with ProcessBuilder, as in Ian's answer, but I found that once things start to get complex, it's easier to write a shell script that does what you want, enabling you to pass as few parameters as possible. Then use ProcessBuilder to invoke the shell script.
If you're invoking anything that has more than really minimal output, you'll also have to read the output and error streams to keep the process from blocking when the output buffers fill, as it seems you are already doing.
I use sudo -S before command and for the tomcat7 user: tomcat7 ALL=(ALL) NOPASSWD:ALL
I am running a shell script through a web application. This shell script looks something like
`#! /bin/bash
user=""
pass=""
db_url=""
db_instance=""
sqlplus -s $user/$pass#$db_url/$db_instance # ./SqlScripts/foo.sql
sqlplus -s $user/$pass#$db_url/$db_instance # ./SqlScripts/bar.sql
CLASS_PATH="./lib/*"
java -classpath $CLASS_PATH package.Main ./Data/inputfile`
I am using ProcessBuilder to run the script and everything but the last line works fine. Am I creating a problem by calling shell through the jvm then calling the jvm again to run the application?
The problem was the environment that the script execution process was running in. I changed some of the environment variables of the process and everything is working fine now. The script was initially a standalone shell script, but I wrote one script for each of the databases used. In order to control the workflow I wrote a web application for this which calls seperate threads for each script and can manage the threads. Thanks for the responses!
Often, app servers run their servlets in a 'clean room' environment - e.g. they strip away all the variables that would normally be set from the outside for security reasons. Try using a fully qualified path to the java binary, and also try setting a full/absolute path for your CLASS_PATH variable.
The parent JVM and the child JVM should be separate processes, no particular reason why they should interfere.
What error do you get?
is java on your PATH?
OK, adding more questions in response to your comments ...
Which thread is waiting? Presumably the parent?
The child java process, do you have any evidence as to whether is succesfully initalises. My guess woukld be that the child is in some way blocked. If you kill the child does the parent then come back to life?
Suppose it was a simple "hello world" application, would that work?
Most likely the line:
CLASS_PATH="./lib/*"
And
$CLASS_PATH
It won't be expanded by the process builder because that's usually shells' job, which in this situation is not being invoked.
Try creating the complete list of ./lib/* and append it directly into the last line of your script.
java -classpath ./lib/a.jar:./lib/b.jar
Side note:
Invoking all this from java looks just bad to me. I would rather have it in a standalone script and invoke it by other means, but that's me.