Start jar file with TimerTask schedule in background in linux - java

I am trying to run my application from a jar file in background. I've already tried nohup and & but they don't work.
nohup java -cp ~/DataGenerator/target/GenerateDataApp-1.0-SNAPSHOT.jar Generator.App -p ~/Text2.txt &
My application is a simple timer that runs every 1s, generating a random number every time and saving it to a file.
public class App {
public static void main(String[] args) throws Exception{
System.out.println("Start");
Arguments arguments = Arguments.fromMain(args);
SaveToFile saveToFile = new SaveToFile();
saveToFile.creatFile(arguments.getPathToPropertiesFile());
Timer timer = new Timer();
timer.schedule(new SaveFileRunner(arguments), 0, 100);
}
}
I also tried the bash script, but it didn't help either.
#!/bin/sh
cd ~/DataGenerator/target
java -cp ~/DataGenerator/target/GenerateDataApp-1.0-SNAPSHOT.jar Generator.App -p ~/Text.txt
Could someone advise me how can I make a timer work in the backend?

To make a program run as a background job, add & to the end of the command line. For example:
java ...parameters here... &
A possible problem with this is if the program writes output, that is still displayed in the terminal. You can send that output to a file.
java ...parameters here... >output.txt 2>&1 &
A second problem is that if you close the shell or logout, the program is stopped. To avoid that, use nohup.
nohup java ...parameters here... >output.txt 2>&1 &

Related

How do I kill a specific java file after one hour, without knowing it's specific PID?

Currently my batch file will launch 20 jars with different arguments, after an hour, a taskkill command kills all java, the batch file will now launch 20 different jars.
My problem is, max cpu usage on startup, and potentially wasted cpu later. I could start the jar files at different times, but then they won't run for equal amounts of time. Takes up to 5 minutes for the cpu usage to half.
I need to launch a jar file, then kill it in an hour, without touching the other 19 jar files, and without knowing the PID.
I have been browsing the web and I see some stuff about, making it a background process, then getting the PID that way, can someone help me out with that?
This is what it looks like now
java -jar file.jar -a first
timeout 3
java -jar file.jar -a second
timeout 3
java -jar file.jar -a third
timeout 3
Use jps.exe utility (which is part of standard JDK) to learn the PID of the just started Java process. Then use taskkill /pid to kill this one process.
I'm just going to have some fun here :)
If you don't have ownership of the jars you might try something like:
public class KillTask extends TimerTask {
private Process process;
public KillTask(Process process) {
this.process = process;
}
#Override
public void run() {
// Prepare to die!
process.destroy();
}
}
public class KillDriver {
public KillDriver(String command) {
try {
Process process = Runtime.getRuntime().exec(command);
new Timer().schedule(new KillTask(process), 60 * 60 * 1000);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
for (String s : args)
new KillDriver(s);
}
}
This example assumes multiple jars will be started but you can alter that for a single or possibly pass in the delay as an argument to add some flexibility.
It appears you are giving the Jars their own process names ("first", "second", "third"), so I assume you could use a VBscript like this that does not require the PID to kill it.
ProcessName = "FIRST"
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate,authenticationLevel=pktPrivacy,(Debug)}!\\.\root\cimv2")
Set colProcessList = objWMIService.ExecQuery("Select * From Win32_Process")
For Each objProcess in colProcessList
If InStr(UCase(objProcess.Name), ProcessName) Then
WScript.Echo "Killing " & objProcess.Name
objProcess.Terminate()
End If
Next

Cron job not running the jar

This is my Java file for which I have created Delete.jar
import java.io.*;
public class Delete {
public static void main(String[] args)
{
try{
int i =1;
while(i<5){
File directory = new File("downloads");
System.out.println("I am running");
for(File file: directory.listFiles()) file.delete();
i++;
}
}catch(Exception e){
e.printStackTrace();
}
}
}
This is my Script to run the jar file if it is not running
#!/bin/bash
processid=`pgrep -f 'Delete.jar high'`
echo "Processes:"$processid
if [ -n "$processid" ]
then
echo "Process is running. No action will be taken"
else
echo "Process is not running. Executing ResponseHandler-fast now !"
cd /home/ubuntu/;
java -jar Delete.jar high
fi
This is line I have added to my crontab -e
* * * * * sh /home/ubuntu/check.sh
I rebooted my System I was expecting that my script will run check that jar is not running and it will run it but it is not doing so.
What I am doing wrong here.
If I execute ps after 2 -3 minutes still I am not getting java as an entry.
Thanks.
Please send output of your shell script to a log file as shown below(make changes to your crontab entry):
* * * * * sh /home/ubuntu/check.sh >> /home/ubuntu/output.log 2>&1
In this way, you will know what exactly is being run and then finding the exact cause will become easier.
Cron doesn't magically make the program "run forever". Start the program manually. It will probably take 1-2 seconds to run, then exit. This is exactly what happens when running with cron, as well. So, unless you run ps the second your program gets started, you won't see anything in the process list.
Your loop 1..5 won't help, as after the files are deleted in the first round, the rest is effectively a no-op.
Did you try running /home/ubuntu/check.sh manually? May be it's not finding the jar file or even java program.

Back to back commands in mac terminal via java Runtime

Basically I have 2 commands I need to execute via a java program the way you would if you were just typing it into terminal.
so like
cd /Users/nameOfUser/Desktop/someFolder/someSubFolder
and then another command I want to execute within that directory. Currently I am doing this:
Process navigate = Runtime.getRuntime().exec("cd /Users/nameOfUser/Desktop/someFolder/someSubFolder");
Process doSomething = Runtime.getRuntime().exec("commandInThatDirectory");
Which doesn't work, it doesn't throw an exception but the second process doesn't seem to take place in the directory specified before it. I am new to processes and runtimes so please bear with me :P.
Is their a way to execute the commands back to back within the same instance of terminal or at least a format for 1 command where you can specify the directory for another command to take place in? I'm a linux user so I don't know mac terminal very well sorry.
It can be done something like this. you can run any command by by placing a semicolon between the commands.
public class Main {
public static void main(String[] args) throws IOException {
ProcessBuilder pb1 = new ProcessBuilder(
"bash",
"-c",
"cd /Users/nameOfUser/Desktop/someFolder/someSubFolder;commandInThatDirectory");
pb1.redirectErrorStream(true);
Process p = pb1.start();
}
}

How to prevent ctrl+c killing spawned processes in Java

[NB. This is related to How do I launch a completely independent process from a Java program? but different]
I want to be able to spawn external processes (shell scripts) from a "manager" Java process that should keep running when the JVM is killed - but it seems that when I kill the parent Java program the child is killed too (note, the behaviour is different if the JVM exits naturally). The simplest test program I have is:
public class Runit {
public static void main(String args[]) throws IOException, InterruptedException {
Runtime.getRuntime().exec(args[0]);
// doesn't work this way either
// ProcessBuilder pb = new ProcessBuilder(args[0]);
// pb.start();
while (true) {
System.out.println("Kill me");
Thread.sleep(2000);
}
}
}
and external script:
#!/bin/sh
while [ 1 ] ; do
ls
sleep 1
done
run as
java -classpath jar-with-dependencies.jar temp.exec.Runit runit.sh
If the manager simply exits (i.e. take out the "while" loop in the Java program) then the spawned process keeps running, but when I Ctrl+c the Java program the external program is killed too which is not what I want.
I'm using OpenJDK 1.6 on Ubuntu.
Edit1: Changing the exec to
Runtime.getRuntime().exec("/usr/bin/nohup " + args[0]);
doesn't help.
Edit2: Adding a shutdown hook as described in How to gracefully handle the SIGKILL signal in Java doesn't stop the Ctrl+c being propagated to the child.
Vladimir gave the hint we needed! (Sorry, beat Lukasz to it)
Add another script spawn_protect.sh
#!/bin/sh
LOG=$1
shift
nohup $* > $LOG 2>&1 &
And change the manager to:
public class Runit {
public static void main(String args[]) throws IOException, InterruptedException {
Runtime.getRuntime().exec(args);
while (true) {
System.out.println("Kill me");
Thread.sleep(5000);
}
}
}
Then run as:
java -classpath jar-with-dependencies.jar temp.exec.Runit spawn_protect.sh /tmp/runit.log runit.sh
Now runit.sh is really detached from the JVM process!
In Linux, if you start another process, it is your child and you are his parent. If parent gets killed, all children get killed, and their children too (what a terrible atrocity).
What you need, is to start a process that won't be killed when you exit your program. So, you need to give birth to not your own child. The methods to do that are described for example here: Linux: Prevent a background process from being stopped after closing SSH client for example use screen utility.
You've got to make it a daemon. Don't be afraid it's not a horror movie. Simply you'll need to detach your processes from controlling terminal session. I've always do it in a oposite way: shell script that launches Java.
Here is an explanation:
http://en.wikipedia.org/wiki/Daemon_(computing)
You can also you "jvm shutdown hooks", but they will not work in some situations.

Runtime.getRunTime().exec not behaving like C language "system()" command

In "C", I can run a long blocking process in the background (AND HAVE IT CONTINUE TO RUN) after the starting process has exited.
void main(void)
{
system("some_long_blocking_process &");
exit();
}
// "some_long_blocking_process" is still running here (DESIRED BEHAVIOR)
Java's getRuntime().exec() DOESN'T have this behavior. Instead, "some_long_blocking_process" ends immediately when the Java process ends.
Anyone know how I can recapture this behavior in Java?
I am using Java 1.4 (No process builder)
I specifically am looking to start the long blocking process and to exit immediately (no "waitFor(), etc.)
Things I have already tried (the process runs correctly, but I still get the same undesired behavior)
adding "nohup" and run in foreground ("nohup some_long_process")
adding "nohup" and running in background ("nohup some_long_process &")
run in foreground ("some_long_process")
run in background ("some_long_process &")
THANKS!
Thanks to all the suggestions... I've decided to use jtahlborn's answer (it worked for me)
try this:
String[] cmd = {"/bin/sh", "-c", "yourcommand args"};
Process p = Runtime.getRuntime().exec(cmd);
when redirect stream to /dev/null:
String[] cmd = {"/bin/sh", "-c", "yourcommand args > /dev/null 2>&1 &"};
Process p = Runtime.getRuntime().exec(cmd);
the only way we were able to achieve this with java was to add another layer of script. you need a simple wrapper script which invokes the app you actually want to run, e.g.:
runner.sh:
#!/bin/sh
nohup "$#" > /dev/null 2>&1 &
then invoke "/bin/sh runner.sh the real command" from your java program.
EDIT:
Have your tried this?
Runtime.getRuntime().exec("/bin/sh -c /usr/X11/bin/xterm &")
This worked for me on MacOS.
Previous answer (JDK 1.5, apologies for not reading the question correctly):
To execute a process without waiting you can use the ProcessBuilder
ProcessBuilder pb = new ProcessBuilder("/usr/X11/bin/xterm");
pb.start();
Your problem is probably due to the trailing &. Try removing it.
getRuntime().exec() is more similar to fork() and exec() than system().
system() passes the command to the shell, and it's Bash that understands that the trailing ampersand means to run the process in the background.
getRuntime().exec() parses the command using a StringTokenizer to parse the command, and doesn't do anything with the trailing ampersand. That's simply passed as the first argument to your some_long_blocking_process, which may exit out immediately on the unknown error.
Have you tried spawning a new Thread to run the executable? Try:
new Thread(new Runnable() {
#Override
public void run() {
try {
Runtime.getRuntime().exec(<your exec>);
} catch (IOException e) {
e.printStackTrace();
}
}
}).run();
This way, the main process won't shutdown until the exec has finished running (and the thread has finished).
Also, don't manually call exit() in your application unless you have some overwhelming reason to--the JVM does a good job of detecting when the application has finished on its own. This way, you won't force close threads that are running in the background.

Categories

Resources