0

I have a java runnable jar which I need to run it if it not running or got killed for some reason so I decided to use crontab for this -

I need to run the crontab as "poppetapp" user so I am logged in as this user and created crontab like this -

*/5 * * * * pgrep -f test_java_10.jar || cd /home/poppetapp && /home/poppetapp/test_java.sh > /home/poppetapp/test_java.out

And my shell script is like this which is in /home/poppetapp/ location -

#!/bin/sh
/usr/home/java -jar /home/poppetapp/test_java_10.jar

My java runnable jar is in the home location for "poppetapp" user which is /home/poppetapp/.

So my question is - Does this look right? I just need to start my test_java_10.jar if it is not running or got killed for some reason so I created a crontab which will run every 5 minutes to check whether it is running or not. If it is not running it will execute my shell script to start the test_java_10.jar process.

But somehow when I make this crontab change, I am seeing lot of test_java_10.jar process is getting invoked. I think every 5 minutes it is launching another process for this.

UPDATE:-

If I modify my crontab like this -

*/5 * * * * pgrep -f test_java_10.jar || /home/poppetapp/test_java.sh > /home/poppetapp/test_java.out

then I see below mail which doesn't say what's the problem or does it say anything?

& t 35
Message 35:
From poppetapp@machineA  Tue Mar 24 17:05:01 2015
X-Original-To: poppetapp
From: root@machineA (Cron Daemon)
To: poppetapp@machineA
Subject: Cron <poppetapp@machineA> pgrep -f test_java_10.jar || /home/poppetapp/test_java.sh > /home/poppetapp/test_java.out
Content-Type: text/plain; charset=ANSI_X3.4-1968
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <HOME=/home/poppetapp>
X-Cron-Env: <PATH=/usr/bin:/bin>
X-Cron-Env: <LOGNAME=poppetapp>
Date: Tue, 24 Mar 2015 17:05:01 -0700 (GMT+7)
david
  • 2,187
  • 7
  • 25
  • 31
  • When you run that pgrep - what return code do you get? You should be able to echo $? right after running it. Does it return a different value if it does/doesn't match? (Because that's what the || is doing, it's not looking at the command output). Personally though, I'd be tempted to suggest a lock file rather than a ps test. – Sobrique Mar 24 '15 at 21:41
  • @Sobrique where do you want me to add echo $?? – david Mar 24 '15 at 21:43
  • Run your pgrep on the command line, echo $? after doing so. But I think I know the problem - pgrep returns 0 if the process is running (e.g. false). – Sobrique Mar 24 '15 at 21:48
  • The cron e-mail you show looks incomplete: it's just headers, with no body. Are you sure it's all there is? The next idea that comes to mind is that $PATH, in the cron environment, doesn't include what is needed to run Java programs. Perhaps append 2>&1 to your script call, so that the error output also ends up in the log file. Or wrap the entire command in parentheses, and append >/tmp/cron.command.log 2>&1 so we see the error output of the entire thing. – dhag Mar 25 '15 at 00:42
  • @dhag you mean to say like this pgrep -f test_java_10.jar || (/home/poppetapp/test_java.sh > /home/poppetapp/test_java.out) > /tmp/cron.command.log 2>&1 – david Mar 25 '15 at 00:48
  • I was thinking (pgrep -f test_java_10.jar || /home/poppetapp/test_java.sh > /home/poppetapp/test_java.out) >/tmp/cron.command.log 2>&1. – dhag Mar 25 '15 at 01:28
  • After running like as you suggested, this is what I see in the file 1445 1447.. These are the PID? – david Mar 25 '15 at 04:41
  • and after another 5 minutes, I saw different PID's 3890 3893 in the same file. – david Mar 25 '15 at 04:46

4 Answers4

1

I think this may be a grouping issue. I replaced your call to pgrep with a simple true or false:

  • If the process isn't running, pgrep will fail:

    $ false || echo cd && echo run
    cd
    run
    
  • If the process is running, pgrep will be successful:

    $ true || echo cd && echo run
    run
    

    In this case, you would want nothing at all to be executed! Running true || (echo cd && echo run) displays nothing, which is what we want.

I suggest trying pgrep -f test_java_10.jar || (cd /home/poppetapp && /home/poppetapp/test_java.sh > /home/poppetapp/test_java.out).

dhag
  • 15,736
  • 4
  • 55
  • 65
  • Thanks for suggestion. I tried doing this but it doesn't work at all. I don't see any java process running if I do it like this but if I run it the way I was doing, it was launching multiple java processes every 5 minutes. – david Mar 24 '15 at 23:09
  • One thing to test would be: does pgrep -f test_java_10.jar ever return true? When your Java program is running, I would expect this command to print the java process PID, and echo $? to print 0. – dhag Mar 25 '15 at 00:28
  • If I am running my java program first, and then if I am running pgrep, yes I can see that printing out the PID. Also if I run like this on the command prompt, pgrep -f test_java_10.jar || /home/poppetapp/test_java.sh > /home/poppetapp/test_java.out. I can see this is also working fine. But when I put this in crontab, then I don't see working – david Mar 25 '15 at 00:39
  • This could be caused by differences of environment between your shell and cron. I added a comment to your question regarding this possibility. – dhag Mar 25 '15 at 00:43
0

The advantage of something like || is it allows you to run something based on a return code. E.g. if the left hand side is false then it evaluates the right hand side, but otherwise it doesn't bother.

Here's the problem though - look at the man page for pgrep:

The pgrep and pkill utilities return one of the following values upon exit: 0 One or more processes were matched. 1 No processes were matched.

So actually, it is 0 and thus false when it matches - so it'll actually only start your java process if it's already running :).

Switch your || to && and you should get the desired result. Although actually, I'd suggest probably putting this into a script so future readers don't have to figure out the same thing.

I would suggest - process grepping is inherently a bit unreliable. You may want to do it via a pid or lockfile instead.

Sobrique
  • 4,424
  • I believe you have it backwards; false, for example, has exit status 1, which is interpreted as false by && (and run true ; echo $? to see true exit with status code 0). That's confusing, for sure, since in other, non-shell contexts 0 usually means false. – dhag Mar 24 '15 at 21:54
  • Hmm, ok. Makes sense. – Sobrique Mar 24 '15 at 22:05
0

JosephR explained the logic better than I can.

I suggest removing the cd /home/poppetapp && and just use the following to get your desired result.

*/5 * * * * pgrep -f test_java_10.jar || /home/poppetapp/test_java.sh > /home/poppetapp/test_java.out
  • Thanks for suggestion. This is pretty strange. If I run it the way you are suggesting me, it doesn't work at all and I don't see any process being launched. But If I use it the way I am running, then it works fine but the only problem is it will launch multiple java processes after every 5 minutes. Pretty strange. – david Mar 24 '15 at 23:07
  • And with your suggestion, it always says this You have new mail in /var/mail/poppetapp and if I go and read it, it doesn't say any error may be I don't know how to read that. – david Mar 24 '15 at 23:50
  • To read the mail type mail followed by ENTER. Then type t XXX followed by ENTER where XXX is the newest entry number. To quit the mail program type q. – Timothy Martin Mar 24 '15 at 23:55
  • I have updated the question with mail details. It doesn't say much I guess. take a look and see whether it makes sense to you? – david Mar 25 '15 at 00:09
0

To avoid issues with the precedence of the || and && operators, just move your logic into the the script:

#!/bin/sh -e

if ! pgrep -f test_java_10.jar >&2; then
    cd "$HOME"
    /usr/home/java -jar ./test_java_10.jar
fi

Then call this script from your crontab every five minutes:

*/5 * * * * "$HOME/test_java.sh"
Kusalananda
  • 333,661