Cronjob command starts 2 processes, for 1 python script - bash

My crontab had the command:
50 08 * * 1-5 /home/MY_SCRIPT.py /home/arguments 2> /dev/null
59 23 * * 1-5 killall MY_SCRIPT.py
Which worked perfectly fine, but when I used to do
ps aux | grep SCRIPT
It showed:
myuser 13898 0.0 0.0 4444 648 ? Ss 08:50 0:00 /bin/sh -c /home/MY_SCRIPT.py /home/arguments 2> /dev/null
myuser 13900 0.0 0.0 25268 7384 ? S 08:50 0:00 /usr/bin/python /home/MY_SCRIPT.py /home/arguments
Why are 2 processes been shown?
And the killall command also used to work fine.
I made a change to my script and in order to get the new behaviour, I had to kill the currently running scripts and I used
kill 13898 13900
After that I used the same command (as in crontab)
/home/MY_SCRIPT.py /home/arguments 2> /dev/null
But now after restarting the script, it showed only 1 process (which makes sense)
Everything looks good till here, but this time the killall MY_SCRIPT in the cronjob didnt work, it said could not find pid. And the script kept on running until I had to manually kill it.
Need to find out the reason for this behaviour:
Why 2 processes from cronjob
Is there something wrong the way I restrated the script
How do I make sure that next time I restart the script, the cron should kill it for sure
OS:Linux Ubuntu

You're seeing two processes because crontab uses /bin/sh to summon your python script. So basically what happens is:
/bin/sh -c '/home/MY_SCRIPT.py /home/arguments 2> /dev/null'
And the process structure becomes
/bin/sh -> /usr/bin/python
Try this format instead:
50 08 * * 1-5 /bin/sh -c 'exec /home/MY_SCRIPT.py /home/arguments 2> /dev/null'
It may also be a good idea to specify the full path to killall. It's probably in /usr/bin. Verify it with which killall.
59 23 * * 1-5 /usr/bin/killall MY_SCRIPT.py
Another more efficient way to do it is to save your process id somewhere:
50 08 * * 1-5 /bin/sh -c 'echo "$$" > /var/run/my_script.pid; exec /home/MY_SCRIPT.py /home/arguments 2> /dev/null'
And use a more efficient killer:
59 23 * * 1-5 /bin/sh -c 'read PID < /var/run/my_script.pid; kill "$PID"'

Related

Run a sh with Xvfb display using cron?

I am trying to run a sh script using cron. This script requires a display.
I have tried:
# Xvfb display
/usr/bin/Xvfb :10 -ac -screen 0 1024x768x24 &
41 18 * * * /bin/sh /path/to/script/script.sh > /path/to/log/log.log 2>&1
Nothing happened and the log.log was not created.
Second try:
43 18 * * * <user> export DISPLAY=:10 /bin/sh /path/to/script/script.sh > /path/to/log/log.log 2>&1
Same result no log file.
(ubuntu) CMD (export DISPLAY=:10 /bin/sh /ibc.paper/twsstart.sh > /crontry.log 2>&1)
Jun 14 18:43:01 CRON[1809]: (CRON) info (No MTA installed, discarding output)
I have been trying all the things I could think of but nothing works.
Can someone tell me what to check?

Why is Bash handling child processes different compared to Sh

The tini init-process, used in Docker, mentions that process group killing is not activated by default and gives the following example:
docker run krallin/ubuntu-tini sh -c 'sleep 10'
If I run this, and press Ctrl-C immediately after, I indeed have to wait for 10 seconds till the child process exits.
However, if instead of sh I used bash:
docker run krallin/ubuntu-tini bash -c 'sleep 10'
and press Ctrl-C, the process exits immediately.
Why do sh (which is symlinked to dash) and bash behave differently towards this child process?
And how does Bash kill the child process, I thought Bash does not propagate signals by default?
Answered thanks to chepner and Charles Duffy:
bash -c has an implicit optimization where it uses exec to replace itself if possible. sh (dash) does not have this optimization. See also this observation.
To verify:
Process tree using bash:
❯ docker run --name test --rm --detach krallin/ubuntu-tini bash -c 'sleep 60'
03194d48a4dcc8225251fe1e5de2dcbb901c8a9cfd0853ae910bfe4d3735608d
❯ docker exec test ps axfo pid,ppid,args
PID PPID COMMAND
1 0 /usr/bin/tini -- bash -c sleep 60
7 1 sleep 60
Process tree using sh:
❯ docker run --name test --rm --detach krallin/ubuntu-tini sh -c 'sleep 60'
e56f207509df4b0b57f8e6b2b2760835f6784a147b200d798dffad112bb11d6a
❯ docker exec test ps axfo pid,ppid,args
PID PPID COMMAND
1 0 /usr/bin/tini -- sh -c sleep 60
7 1 sh -c sleep 60
8 7 \_ sleep 60

Start nginx from shell script on crontab

I want to check NGINX is running or not every 1 minute.
My shell script is:
#!/bin/sh
ps auxw | grep nginx | grep -v grep > /dev/null
if [ $? != 0 ]
then
echo "NGINX is not running"
/etc/init.d/nginx start
else
echo "NGINX is running"
fi
Script run with sh launch.sh correctly (If NGINX is not running, run NGINX).
The problem is when I want to run the script every 1 minute by crontab, nothing happens. Crontab list is here:
# Edit this file to introduce tasks to be run by cron.
#
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
#
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').#
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
#
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
#
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
#
# For more information see the manual pages of crontab(5) and cron(8)
#
# m h dom mon dow command
* * * * * ~/sh launch.sh
I test * * * * * sh launch.sh, * * * * * launch.sh and * * * * * ./launch.sh but none of them work correctly.
My OS is UBUNTU 18.04.
This is log:
Jun 3 08:28:01 hajitsu-VirtualBox CRON[3239]: (root) CMD (~/launch.sh)
Jun 3 08:28:01 hajitsu-VirtualBox CRON[3240]: (hajitsu) CMD (/home/hajitsu/launch.sh)
Jun 3 08:28:01 hajitsu-VirtualBox CRON[3238]: (CRON) info (No MTA installed, discarding output)
Jun 3 08:28:01 hajitsu-VirtualBox CRON[3237]: (CRON) info (No MTA installed, discarding output)
Jun 3 08:29:01 hajitsu-VirtualBox CRON[3374]: (root) CMD (~/launch.sh)
Jun 3 08:29:01 hajitsu-VirtualBox CRON[3373]: (CRON) info (No MTA installed, discarding output)
Jun 3 08:29:01 hajitsu-VirtualBox CRON[3376]: (hajitsu) CMD (/home/hajitsu/launch.sh)
Jun 3 08:29:01 hajitsu-VirtualBox CRON[3372]: (CRON) info (No MTA installed, discarding output)
I think the command fired but nothing happend.
NGINX needs sudo privilege.
If you have sudo privileges you can modify /etc/sudoers.d/username file and execute sudo commands without password.
The file usually contains a user and a list of commands that the user can run without having to specify a password. In your case, you can run:
sudo /etc/init.d/nginx start
Add or modify your sudoers file. (replace username with your username.)
$ EDITOR=nano sudo visudo -f /etc/sudoers.d/username # EDITOR=nano sets my editor (because I am more comfortable with nano)
Copy and paste following.
You can add more sudo commands separating by comma.
username ALL=(ALL) NOPASSWD: /etc/init.d/nginx start,/etc/init.d/nginx start
Note: Commands will only execute called with sudo.
Prepend sudo in your launch.sh:
#!/bin/sh
ps auxw | grep nginx | grep -v grep > /dev/null
if [ $? != 0 ]
then
echo "NGINX is not running"
sudo /etc/init.d/nginx start
else
echo "NGINX is running"
fi
Make file executable.
$ chmod +x launch.sh
~ won't be expanded the way it is in an interactive shell when in a crontab. Use /home/username instead.

Crontab script su root / user -c does not execute

if been trouble-checking for hours and can't find out why my shell script won't execute properly when using a root crontab.
I'm on a vServer eqipped with
Ubuntu 14.04.4 LTS
3.13.0-042stab113.11.
my script is a chmod 711 file:
/usr/local/sbin/bckup_script
and looks like this:
#!/bin/bash
DATE=`date +%Y-%m-%d_%H_%M_%S`
su - -c "chgrp postgres /backup/db"
su - -c "chmod 770 /backup/db"
su - -c "chown user /backup/db"
su - postgres -c "pg_dump db_name > /backup/db/${DATE}db_name.sql && pg_dumpall > /backup/db/${DATE}_all_db.out"
su - -c "rsync -a /home/user/value /backup/"
The crontab is started using
crontab -e
as
root
user
The crontab executes as far as I can tell from syslog.
When executed as root user (no crontab), the file will do what it's told to. Also my PATH is set properly and working.
I have no idea what am doing wrong.
Solution:
Thx to Jay jargot I found out what was wrong. To complete the question, here are the outputs you "asked" for:
crontab -l
#m h dom mon dow command
* * * * * bckup_script
Output of crontab was
/bin/sh: bckup_script: command not found
which lead me to the conclusion to use the absolute Path to the file which solved the problem.
my crontab -l now looks like follows and everything works like a charm!
# m h dom mon dow command
49 20 * * 1-5 /usr/local/sbin/bckup_script
Thx very much!

Why docker exec is killing nohup process on exit?

I have running docker ubuntu container with just a bash script inside. I want to start my application inside that container with docker exec like that:
docker exec -it 0b3fc9dd35f2 ./main.sh
Inside main script I want to run another application with nohup as this is a long running application:
#!/bin/bash
nohup ./java.sh &
#with this strange sleep the script is working
#sleep 1
echo `date` finish main >> /status.log
The java.sh script is as follow (for simplicity it is a dummy script):
#!/bin/bash
sleep 10
echo `date` finish java >> /status.log
The problem is that java.sh is killed immediately after docker exec returns. The question is why?
The only solution I found out is to add some dummy sleep 1 into the first script after nohup is started. Than second process is running fine. Do you have any ideas why it is like that?
[EDIT]
Second solution is to add some echo or trap command to java.sh script just before sleep. Than it works fine. Unfortunately I cannot use this workaround as instead of this script I have java process.
This is not an answer, but I still don't have the required reputation to comment.
I don't know why the nohup doesn't work. But I did a workaround that worked, using your ideas:
docker exec -ti running_container bash -c 'nohup ./main.sh &> output & sleep 1'
Okay, let's join two answers above :D
First rcmgleite say exactly right: use
-d
options to run process as 'detached' background.
And second (the most important!) if you run detached process, you don't needed nohup!
deploy_app.sh
#!/bin/bash
cd /opt/git/app
git pull
python3 setup.py install
python3 -u webui.py >> nohup.out
Execute this inside a container
docker exec -itd container_name bash -c "/opt/scripts/deploy_app.sh"
Check it
$ docker attach container_name
$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 11768 1940 pts/0 Ss Aug31 0:00 /bin/bash
root 887 0.4 0.0 11632 1396 pts/1 Ss+ 02:47 0:00 /bin/bash /opt/scripts/deploy_app
root 932 31.6 0.4 235288 32332 pts/1 Sl+ 02:47 0:00 python3 -u webui.py
I know this is a late response but I will add it here for documentation reasons.
When using nohup on bash and running it with 'exec' on a docker container, you should use
$ docker exec -d 0b3fc9dd35f2 /bin/bash -c "./main.sh"
The -d option means:
-d, --detach Detached mode: run command in the
background
for more information about docker exec, see:
https://docs.docker.com/engine/reference/commandline/exec/
This should do the trick.

Resources