This question may seem weird, so here is why we need it. Our test infrastructure relies on Fitnesse framework with different fixtures. One of the fixtures is running a groovy script like that:
cmd /c groovy_runner.bat myScript.groovy Param1 ParamN
groovy_runner.bat:
set JAVA_OPTS="-Xmx1024M"
set groovyCP="<list of jars>"
groovy -cp %groovyCP% %*
So, we have a process tree like java (Fitnesse) => cmd (cmd /c groovy_runner.bat) => java ("C:\Program Files\Java\jre6\bin\java.exe" "-Xmx128m" -Dprogram.name="" -Dgroovy.home="C:\groovy-2.1.3\bin.." -Dgroovy.starter.conf="C:\groovy-2.1.3\bin..\conf\groovy-starter.conf" -Dscript.name="c:\Scripts\WebDriver\myScript.groovy" "-Xmx1024M" -classpath "C:\groovy-2.1.3\bin..\lib\groovy-2.1.3.jar" org.codehaus.groovy.tools.GroovyStarter --main groovy.ui.GroovyMain --conf "C:\groovy-2.1.3\bin..\conf\groovy-starter.conf" --classpath "" myScript.groovy Param1 ParamN
And sometimes groovy script hangs. Currently, we don't understand the reason why it hangs, but just wanted to know if it possible to somehow restrict the time the groovy script may be running. Say, is it possible to somehow specify in the groovy script or groovy config files that it is expected to run no more than 15 minutes, otherwise it has to be forcibly stopped?
Is it doable?
Thanks,
Racoon
I don't know of any way to do this within Groovy's config. Better would be write another script, which waits fifteen minutes and then kills the first one if it exists.
Related
I need to automatically execute some perl scripts from Java. I use Runtime.getRuntime().exec to start the perl process. I generate a start-parameter-string and pass it as an argument to exec. The String looks somewhat like this:
cmd /C start /wait perl "path\to\perl\script" -p1 scriptparameter1 -p2 scriptparameter2
I also tried
perl "path\to\perl\script" -p1 scriptparameter1 -p2 scriptparameter2.
If I copy that String and execute it via Windows+R everything works, but via exec the Perl-scripts can't find the svn-command. Why does it make a difference if I execute the perl process from java instead of directly from windows?
I figured it out. The reason was that I had just installed svn and the PATH envirment variable took effect for cmd but not for other processes (for whatevery reason). After a computer restart everything works as expected.
I'm trying to restart process when OOME happens. Java binary is launched using two shell scripts, one of them imports other. I don't have any control of the first one but can modify the second one as I want.
This is a prototype what I'm trying to do:
First shell script test.sh:
#!/bin/sh
JAVA_OPTS="$JAVA_OPTS -Xmx10m"
. test1.sh
echo $JAVA_OPTS
java $JAVA_OPTS $es_params TestMemory
Second shell script test1.sh:
#!/bin/sh
pidfile="test.pid"
touch $pidfile
params="$parms -Dpidfile=$pidfile"
kill_command="kill -9 \$(cat $pidfile)"
dir=$( cd $(dirname $0) ; pwd -P )
path="$dir/$(basename $0)"
start_command="$path $#"
restart_command="$kill_command;sleep 2;$start_command"
JAVA_OPTS="$JAVA_OPTS -XX:OnOutOfMemoryError=\"$restart_command\""
Generally what it does is JAVA_OPTS is constructed inside test1.sh and then used to run Java binary, which just writes PID in pidfile and then creates OOME.
Problem happens during execution, java can't understand what is a parameter and what is a class to run. I think it might be a problem of quoting, I tried different ways to escape JAVA_OPTS, but without any result. I'm either getting:
Unrecognized option: -9
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
Or
Error: Could not find or load main class "-XX:OnOutOfMemoryError=kill
If I just take a value of JAVA_OPTS and put it manually in test.sh it runs perfectly.
Any ideas how can I change test1.sh to make it work? I think I tried almost every possible way of putting double and single quotes, but without any success. Also if I put restart_command in restart.sh file and use it instead of the variable, it works fine.
After running set -x I saw that shell modifies every single space character to ' ' - adds ' on both sides. Escaping doesn't gives any result. Any idea how to avoid this? So final commend is:
+ java -Xmx10m '"-XX:OnOutOfMemoryError=kill' '$(cat' 'test.pid);sleep' '2;/Users/davidt/test/TestMemory/bin/test.sh' '")' -Des.pidfile=test.pid TestMemory
Update
I can run simplified command successfully
java "-XX:OnOutOfMemoryError=echo 'Ups'" $es_params TestMemory
But it seems a general problem, shell just hates spaces into variables I guess:
JAVA_OPTS="\"-XX:OnOutOfMemoryError=echo 'Ups'\""
set -x
java $JAVA_OPTS TestMemory
This script fails and the last line is interpreted as:
java '"-XX:OnOutOfMemoryError=echo' ''\''Ups'\''"' TestMemory
I tried different options to escape
This is a shell problem. Based on the evidence, I'd say that one of the ; characters ... and possibly some why space ... is being interpretted by the shell when you don't want / need this to happen.
If you run set -x in the shell before running the command that is trying to start the JVM, you will see the actual command that is being used.
It seems shell translates every single space to ' ',
Not exactly. The single quotes are inserted by the shell into the output you are getting from set -x. They simply indicating where the argument boundaries are. They are not really there ... and they are certainly NOT being passed to the java command.
Any idea how to [a]void it?
What you need to do is start from the (final) command that you are trying execute ...
java -Xmx10m -XX:OnOutOfMemoryError="kill NNNN;sleep 2;/Users/davidt/test/TestMemory/bin/test.sh" -Des.pidfile=test.pid TestMemory
... and work backwards, so that the shell variables, expansions and escaping give you what you need.
The other thing to note is that this:
java -Xmx10m -XX:OnOutOfMemoryError="kill $(cat test.pid); ..."
probably won't work. The kill $(cat test.pid) command is using shell syntax and requires shell functionality to interpolate the contents of the PID file. I doubt that the JVM is going to know what to do with that. (Or more accurately. It will do what you have literally told it to do, but that will not be what you want ...)
If you really need to interpolate the pid file content when the restart command is run as you appear to be trying to do, then suggest that turn the restart command into a free-standing shell script, and set the file mode so that it is executable. It will be simpler and a lot easier to get working.
As a general piece of advice, is is a bad idea to be too clever with shell scripts. The exact semantics of variable expansion and command parsing are rather tricky, and it is easy to get yourself really confused ... if you are trying to do this at multiple levels.
I ended up put the script I wanted to execute in a separate file and gave it as a parameter to JVM to execute when OOME happens.
echo "echo 'UPS'" >> oome_happened.sh
JAVA_OPTS="\"-XX:OnOutOfMemoryError='oome_happened.sh'\""
set -x
java $JAVA_OPTS TestMemory
Like #DaTval said, you should put the command in a script. The script should be someting like.
#!/bin/bash
kill -9 $PPID
Kill the caller of scripts.
I'm not sure what to tag this with, but I need help combining two commands into a single command. I've tried this with ant, but it doesn't perform as required (long story). Essentially I need
javac *.java
java org.junit.runner.JUnitCore filename
To be consolodated into a single command. Preferrably something like
ant
with an external build.xml file, however after several hours fiddling with Ant I've gotten it to work but not as required (I need continuous output to stdout during runtime). I'm fine with shell scripts, clever java tricks, anything. I'll take what I can get at this point.
Writing a shell script is really a trivial matter: just copy-paste those exact two lines into a file (say you call it myscript.sh) and you're done. Then you can run it with sh myscript.sh. For added convenience add a first line that says #!/bin/sh (the so-called "hash-bang" incantation), issue a chmod u+x myscript.sh, and then you can run it as any other command: ./myscript.sh.
BTW this turned out into a question unrelated to Java, you might retag it with a shell script-related tag.
I am using a java program which sends email after finishing up some file transfers.I am using Eclipse to code up the program. How do I set up a cron job to execute this java program for a particular time. Also I have various jar files inside the project. Please suggest
Write a shell script to invoke your java program with the necessary
arguments.
Make sure that the classpath argument points to the jars that you need.
Make sure that the shell script has necessary unix
permissions.
Schedule the script to be invoked by setting up a cron
job.
For more info about cronjob look here http://en.wikipedia.org/wiki/Cron
just my 2 cents...
r0ast3d has a quick, clear answer - I did have to do some more searching to get each step done so I'll elaborate on his steps:
Write a shell script to invoke your java program with the necessary arguments.
Example:
!/bin/bash
echo "Running script."
cd ~/your/classpath/to/java
java -classpath .:somejar.jar path/to/your/Program
Separate your necessary classpaths with colons (:) rather than semicolons (;)
The path to your program should start with your package (find this at the top of the java program)
Make sure that the classpath argument points to the jars that you need.
You can check your import statements in your java program to make sure you are specifying all the necessary classpaths. You have to run this script from your java directory, and can use a single period (.) as your first classpath argument.
Make sure that the shell script has necessary unix permissions.
Run from a terminal: sudo chmod ### yourScript.sh
Where ### are numbers representing the correct permissions for your system setup.
Schedule the script to be invoked by setting up a cron job.
Run from a terminal: crontab -e
This will open your crontab editor. You can add a job in this way:
*/5 * * * * bash /home/scripts/yourScript.sh
Replace the path to the script with the correct location of your script. This job is set to run every 5 minutes. See http://www.adminschoice.com/crontab-quick-reference/ for a good reference on crontab.
Hope this helps someone out!
use quartz for more complex need or Timer for a simpler task
There is the cron4j library http://www.sauronsoftware.it/projects/cron4j/. I have used it before to schedule a java program to run weekly. The scheduling syntax is the same as a crontab. The thing is, it needs to be constantly running as a background process to work. I ended up just using normal cron, but it could be useful if you're not on an Unix-like system, and you don't have cron.
I have a java application and I want to run a script whenever it experiences and OutOfMemoryException
This works great:
$ java -server -XX:OnOutOfMemoryError="./oom_script %p" TestOOMClass
Unfortunately my application is run by a bash script in production. The script boils down to this:
cmd='java -server -XX:OnOutOfMemoryError="./oom_script %p" TestOOMClass'
##does a lot of checking and cmd building here
exec -a app ${cmd}
When run like this java never respects the double quotes and thinks %p is the class. how do I prevent this? I've tried double escaping but that doesn't work.
Since your program is run as a shell script, I would suggest putting this as the first line in your shell script after the shebang:
set -xv
Then, in the crontab, put 2>&1 at the end of the command line, so STDERR and STDOUT are merged. Crontab usually emails out the STDOUT of a command to root, so you can see what the output is. If not, then apend the following to the end of the command in your crontab:
> /somedir/output.$$ 2>&1
Make sure somedir exists, and after crontab runs your command, you'll see the verbose and debug output. Each line in your shell script will be displayed before it is executed -- both as written and as the shell actually interprets it.
The set -xv becomes very useful in debugging any sell script. There could be all sorts of environmental issues involved between the cronjob and the script running under your login. You might even find a shell issue. For example, crontab usually executes shell scripts in Bourne shell and you probably have Bash or Kornshell as your default shell. Whatever it is, you'll usually find out the issue very quickly when you turn on verbose/debug mode.
You don't even have to do this to the entire script. You can put set -xv anywhere in your script to turn on verbose/debug mode, and set +xv to turn it off.
I could make several pious high minded recommendations (use quotes, don't assume environment things, prefix your command line with "bash -c" to make sure you're using the right shell, etc.), but this would be guessing what could be wrong. In order to really debug this issue, I would need to see the machine, know the OS, see your entire shell script, and understand the entire environment. And, the first thing I would do is add set -xv in your shell script.
Quotes and escaping is an art. I would suggest you add echo ${cmd} before calling exec so you can see what it looks like then.
I would suggest using
cmd='java -server -XX:OnOutOfMemoryError=\\"./oom_script %p\\" TestOOMClass'
instead (untested). You need it to look like \" when being echoed.
an alternative i suggest (to bypass the problem, not solve it indeed) is to rung and bash script and access the $PPID:
PPID The process ID of the shell's parent. This variable is readonly.
then kill the process with that ID (please bare in mind that is an untested suggestion)