Linux process restarter - linux

I would like a script that does something along the lines of:
if process_name not running
start process from path /home/data/process_name
write "date: process start" to /home/data/log.txt
I have never written a bash script, and I dodn't know what to do.

On Debian and Ubuntu you can use start-stop-daemon. It has all sorts of options to help identify the right process so that you don't end up starting it twice or killing the wrong one. An example from the man page:
Start the food daemon, unless one is already running (a process named
food, running as user food, with pid in food.pid):
start-stop-daemon --start --oknodo --user food --name food --pidfile /var/run/food.pid --startas /usr/sbin/food --chuid food -- --daemon
This command makes sure that the process belongs to the right user, has the right name, and has a process id matching that in /var/run/food.pid. You don't have to use them all, of course.

Try this:
if ! pgrep process_name; then
/home/data/process_name &
echo "$(date): Process start" >> /home/data/log.txt
fi
If do you want to kill process and then start it, try this:
if ! pgrep process_name; then
/home/data/process_name &
echo "$(date): Process start" >> /home/data/log.txt
else
killall process_name
/home/data/process_name &
echo "$(date): Process start" >> /home/data/log.txt
fi

Related

How to run a second process with dependency to a running process using shell script?

I want to do an automation for 2 processes using shell script.
I have 2 programs, a is a workload, b is a CPU profiler to profile the cpu when a is running.
Previously, I run these programs manually, by opening 2 terminals. First, run a in the first terminal, then in another terminal, I get the process ID of a, and finally run ./b [pid-of-a]. This has caused me to miss the profiling of the first few seconds of process a.
I tried:
./a &
pid=$! &
./b pid
But it does not work the way I wanted. It runs b first and returns an error because the PID of a does not exist. I can't use && as well because it will wait a to finish first before b starts which is not the way I want.
What modification should I do to my code regarding such dependency?
Don't set pid in the background, and remember to put a $ when you want to expand it:
./a &
pid=$!
./b "$pid"
Or just
./a &
./b $!
Write a bash script which will check for ProcessA using pgrep and gets its pid
#!/bin/sh
while true
do
pid=`pgrep -f processA`
if [ ! -z $pid ]
then
./processB $pid
break
fi
done

Not able to stop init script using start-stop-daemon

I want to use start-stop-daemon to stop the scripts it has started, but currently the scripts are not killed, and so I have resorted to hacking around it:
#!/bin/sh
case $1 in
start)
start-stop-daemon --start --background -c myapp --exec /home/myapp/dev-myapp.sh
;;
stop)
# couldn't get this to work - hacking around it
#start-stop-daemon --stop -c myapp --exec /home/myapp/dev-myapp.sh
# hack
killall dev-myapp.sh
sleep 3
killall -9 dev-myapp.sh
;;
restart)
$0 stop
$0 start
;;
*)
echo "No such command. "
echo "Usage: $0 start|stop|restart"
esac
exit 0
How can I get the script to kill the bash scripts it has started using start-stop-daemon?
edit: I assume the failure to stop the processes has to do with this section from the man page:
-x, --exec executable
Check for processes that are instances of this executable. The executable argument should be an absolute pathname. Note: this
might not work as intended with interpreted scripts, as the executable will point to the interpreter. Take into account processes
running from inside a chroot will also be matched, so other match restrictions might be needed.
So I might be forced to rely on name detection instead, but I don't know what the process name is ... Is this the whole absolute filename, the filename alone, or something else?
Regarding your comment, if you're willing to extend the shellscript you are running, you can use a pidfile. In practice, maybe you want to make it an option to your script, but as an example, this line would be sufficient:
echo $$ >/var/run/dev-myapp.sh.pid
Then, use these matching parameters for start-stop-daemon, if necessary replacing /bin/bash with whatever shell executes your script:
-p /var/run/dev-myapp.sh.pid -x /bin/bash
(To clarify: The process name of the script is that of the script interpreter, in your case, the shell)

Get PID of backround process lauched as other users

I'm trying to store the PID of a background process I need to launch as a non-root user.
When I execute the script below, the PID file is created but stays empty.
USER=myuser
PROG=/path/to/service
PROG_ARGS=""
PIDFILE=/var/run/$NAME.pid
su $USER -c "python2.7 $PROG $PROG_ARGS &"
echo $! > $PIDFILE
I've tried to place the & outside the su command like so su $USER -c "python ..." &, and it nearly worked since I get a PID but it's always the one before my actual process (Eg: if my python PID is 3101, the saved PID will be 3100). I suspect this is the PID of the shell that launched the python script.
My question is, how can I launch my python script as a specific user and save the PID at the same time?
I'm running RHLE 6.
The background process is created in the subshell started by su, so you need to capture $! there.
su $USER -c "python2.7 $PROG $PROG_ARGS & echo \$! > $PID_FILE"

In Bash, Kill background function will not kill internal process, why they have different pid?

For convenience, I put my server command into a function, but I background the function got a pid is not my server's pid.
myserver(){
# May contain complicate parameter
sleep 10
}
myserver > my.log &
pid=$!
ps aux|grep sleep
echo "Found PID " $pid is different from ps
So, if I kill $pid will not kill real server process(here is sleep).What should I do ?
UPDATE
sleep 10 &
pid=$!
ps aux|grep sleep
echo Found PID $pid is same
UPDATE
In this case
myserver(){
# May contain complicate parameter
sleep 10
}
myserver > my.log &
kill $!
Will kill the sleep process, but actually, my server is java -jar, when I do kill $!, the java process will not get killed.
In order to kill via the kill command you should provide the PID and not the Job Id.
Check this post about JID and PID
Update on Comment:
Are u sre you are providing it right?
In my system:
$ sleep 20 &
[2] 10080
$ kill -9 $!
[2]- Killed sleep 20
$
Folow up
Ok now I get it. Sorry i misinterpretted your question. What you describe is the expected behavior:
$! Expands to the decimal process ID of the most recent background command (see Lists) executed from the current shell. (For example, background commands executed from subshells do not affect the value of "$!" in the current shell environment.) For a pipeline, the process ID is that of the last command in the pipeline.
So in that case maybe try this proposed solution
Update on Question:
Ok, in the case of java proces I would try a regexp:
pkill -f 'java.*<your process name or some -classpath jar or something unique to the process you want to kill>'
In fact, any string or classpath jar that came along with this command and would result to a match would do the job.

Upstart: Error when using command substitution in post-start script stanza during startup sequence

I'm seeing an issue in upstart where using command substitution inside a post-start script stanza causes an error (syslog reports "terminated with status 1"), but only during the initial system startup.
I've tried using just about every startup event hook under the sun. local-filesystems and net-device-up worked without error about 1/100 tries, so it looks like a race condition. It works just fine on manual start/stop. The command substitutions I've seen trigger the error are a simple cat or date, and I've tried using both the $() way and the backtick way. I've also tried using sleep in pre-start to beat the race condition but that did nothing.
I'm running Ubuntu 11.10 on VMWare with a Win7 host. Spent too many hours troubleshooting this already... Anyone got any ideas?
Here is my .conf file for reference:
start on runlevel [2345]
stop on runlevel [016]
env NODE_ENV=production
env MYAPP_PIDFILE=/var/run/myapp.pid
respawn
exec start-stop-daemon --start --make-pidfile --pidfile $MYAPP_PIDFILE --chuid node-svc --exec /usr/local/n/versions/0.6.14/bin/node /opt/myapp/live/app.js >> /var/log/myapp/audit.node.log 2>&1
post-start script
MYAPP_PID=`cat $MYAPP_PIDFILE`
echo "[`date -u +%Y-%m-%dT%T.%3NZ`] + Started $UPSTART_JOB [$MYAPP_PID]: PROCESS=$PROCESS UPSTART_EVENTS=$UPSTART_EVENTS" >> /var/log/myapp/audit.upstart.log
end script
post-stop script
MYAPP_PID=`cat $MYAPP_PIDFILE`
echo "[`date -u +%Y-%m-%dT%T.%3NZ`] - Stopped $UPSTART_JOB [$MYAPP_PID]: PROCESS=$PROCESS UPSTART_STOP_EVENTS=$UPSTART_STOP_EVENTS EXIT_SIGNAL=$EXIT_SIGNAL EXIT_STATUS=$EXIT_STATUS" >> /var/log/myapp/audit.upstart.log
end script
The most likely scenario I can think of is that $MYAPP_PIDFILE has not been created yet.
Because you have not specified an 'expect' stanza, the post-start is run as soon as the main process has forked and execed. So, as you suspected, there is probably a race between start-stop-daemon running node and writing that pidfile and /bin/sh forking, execing, and forking again to exec cat $MYAPP_PIDFILE.
The right way to do this is to rewrite your post-start as such:
post-start script
for i in 1 2 3 4 5 ; do
if [ -f $MYAPP_PIDFILE ] ; then
echo ...
exit 0
fi
sleep 1
done
echo "timed out waiting for pidfile"
exit 1
end script
Its worth noting that in Upstart 1.4 (included first in Ubuntu 12.04), upstart added logging ability, so there's no need to redirect output into a special log file. All console output defaults to /var/log/upstart/$UPSTART_JOB.log (which is rotated by logrotate). So those echos could just be bare echos.

Resources