Does cron job executing script cancel each other - cron

I can't wrap my head around this concept
If a cron job is set to execute a particular script every 5 minutes and the task the script is performing happens to be very long
What will happen if cron job re execute the script after 5 minutes and the script is not done executing the prior task will this cause the prior task to abort and restart again
Or will the server know its suppose to queue it and wait for the prior task before re executing the script

It is neither. The two tasks overlap, and run at the same time.
Cron jobs don't cancel each other unless they try to lock and access the same files, or the scripts have some other conflicts. You can of course make them cancel each other if you want, though.
The server is none the wiser, and the tasks don't wait for previous executions unless you explicitly add such details, for example, by using flock or pgrep to check for previous executions still running.
The following example entry in cron tab checks if the script is already running, and only runs if the script (cron.sh) is not already running.
* * * * * /usr/bin/pgrep -f /path/to/cron.sh > /dev/null 2> /dev/null || /path/to/cron.sh

Related

Does cron monitor exit codes for a job, I have a cron job that is getting restarted

I have a cron job set to run a python script say script.py, I have set the cron to run it every 6 hours. The issue is that when the script is getting run, it keeps starting the process again and again. The python script has a few sleeps in it. Technically the script runs and exits when run standalone. For some reason I see the cron trying to start the process again and again.
* */6 * * * python3 /path/to/script.py
I have read answers on using locks and pid files, asking this just to understand the behaviour.
I think that your problem is not that your job is getting restarted after terminating, it will be executed every minute. If you enter a ´*´ this stands for every possible value. So when you enter EVERY VALUE for your minutes, your task is getting executed every minute. Instead, you should use:
0 */6 * * * python3 /path/to/script.py
Hope this solves your problem

Cron job runs multiple times in an available VMs in the same timing

I have to run a script in cron, where I am keeping cron entry in /etc/cron.d directory.
So here how my cron entry looks like (in /etc/cron.d/cron_for_abd_list.cron):
30 * * * * /home/usr/vinod/ABD_List/Cron_script_V1.pl > /home/usr/vinod/ABD_List/LOG/Log_Cron_`date +\%y\%m\%d_\%H`.txt 2>&1
So my cron script will be running each hour 30th minute and storing the Logs in LOG directory i.e., /home/usr/vinod/ABD_List/LOG/
Actually the system is configured in such a way that where this cron will run in 2 servers at a time. Because that is how the environment is configured.
I have hosts called serv-1-sms and serv-2-sms and when I keep this cron entry in /etc/cron.d/ directory it would trigger in both the hosts at a time.
So, in order to avoid it to run multiple times in same timing I have used a below logic inside a script.
Logic is, when the script starts running (either from serv-1-sms or serv-2-sms) it will first check for the dummy file tempfile.txt in the same directory(ABD_List). If it already exists then process will be terminated, else script will continue running and at the end it will delete tempfile.txt which is been created at the beginning.
use strict;
use warnings;
my $filename = "/home/usr/vinod/ABD_List/tempfile.txt";
if (-e $filename) {
print "File already exists.. Exiting: $$\n";
exit 0;
}
system("touch $filename");
...
#executing the rest of the things in the scripts
...
unlink $filename;
print "END\n";
This is how I am avoiding collision of running same script at same time.
I this logic is bit weird. If any alternate logic available please suggest me or if we can control this collision in crontab itself that would be more helpful.

How to stop minute cron job?

I have a program written in python,my program scrapes a value from some financial website every minute and pushes that value into my DB.My program takes like 1 or maximum 1.5 seconds to do this job. I have set a cron job to call my program every minute. I need to run my program in this way everyday from 09AM to 04PM. Now sometimes I may have to stop my program to kill the program at any time between 09AM to 4PM. How can I do this?
According to this link
I tried ps -o pid,sess,cmd afx | grep -A20 "cron$" and I was unable to find my program in the list since it completes it's work in seconds.
Referring to this I tried /etc/init.d/cron stop and pkill cron which kills all cron jobs which I don't want. I am running this cron in ubuntu linux .Any help with this would be appreciated.
Modify the program so it runs only if a particular file exists. Remove the file if you need to stop the program. (Or have it run only if the file doesn't exist, and touch the file to stop the program.)
If you're not able to modify the program, you can execute a shell if statement as a cron command.
simply rename the script name, so it will not be executed
Is it feasible to include a date time check within the program? And it won't run if before 9AM or after 4PM?
The following should also work:
* 9-15 * * * script.sh
0 16 * * * script.sh
To switch: perhaps have it read from a config/detect the presence of a file (acting as a flag) to determine whether or not to run.

How to test the script deployed with crontab

I have a script which I need to run daily at 01.00 am of every month. This is what I did with cron tab to make it happen
#housekeeping
0 1 1 * * sh /product/abc/tools/housekeeper.sh -t ABC
How can I check whether this script is running? Do I have to wait till it runs or is there a process running for this script so that I can confirm it is running?
The usual approach to test crontab scripts follows these guidelines:
Set the time pattern to "ten minutes from now". Wait ten minutes. Check cron's logfile and the log files of your script/app for errors.
Set the desired time pattern
This way, you can make sure that the script works. If something breaks, it must be because of the time pattern.
You should also redirect all output of the script to a log file. cron will send a mail with any output that the script produces but that's rarely desired.
If you always add an entry like "${timestamp} Started" to the log, you can check at your leisure that the script worked as expected.
If you want both, then you must make your script/app write the log file itself (i.e. without output redirection in the crontab) and print any errors to stdout; this will then make cron send an email.
Simple thing I use is to append something to a particular file before and after the desired command, like
*/2 * * * * (echo "Starting" >> ~/monitorCron.log; <Actual operation>; echo "End" >> ~/monitorCron.log;) > ~/cron.log 2>&1
This runs every 2 minutes, and appends the strings to ~/monitorCron.log.
This is the same thing I do in programming, writing a print statement where-ever and when-ever I get a doubt.

Code for stopping the overlapping of the Cron job

I need to stop the overlapping of cron jobs for example:If a cron job is scheduled at morning 2 o clock for DB backup and other cron job is scheduled at morning 7 o clock for DB backup again.So i need to stop the 7 o clock scheduled cron job if the DB backup for 2 o clock is not completed.
This is what flock is for. From man flock:
...
The third form is convenient inside shell scripts, and is usually used
the following manner:
(
flock -n 9 || exit 1
# ... commands executed under lock ...
) 9>/var/lock/mylockfile
...
In this case, flock will try to get a lock on fd 9 for /var/lock/myfile. If it can't (because the earlier job is still running), it will exit.
You need to put it in a script.
The most straightforward way to do this would be to have your 2am and 7am tasks coordinate. So for instance, the DB backup script could create a lock file when it executes, and check for the existence of this file when it starts up. If the file exists it could simply exit without doing any work (or sleep for a bit, or whatever you decide).
Doing this in a completely task-agnostic way might be possible, but it's going to be trickier and unnecessary in this particular case.
Assuming you are on a Unix system: The easiest way to do this is
create a file and write the cron job's PID to it. If the file can't be
created using open(2) with O_CREAT|O_EXCL flags, it already
exists, thus the previous job is still running or has crashed without
cleaning up. The PID can be used to determine whether the job is still
running.
In your case, the safest approach is probably for the cron job to die
if the PID file is found on startup.
Since you put the perl tag to the question, I suggest to have a look
at the File::Pid and Proc::PID::File modules.
You just need something that you can check to see if the first task has finished running, and this check should be done right before the job runs again.
I'd implement this with a database (if available) or a registery key or even a text file. So your task would look like this:
read job_flag
if job_flag == 0
step job_flag = 1
run job
step job_flag = 0
else
stop job
end
Why not just do this in a single cron job?
/path/to/job1 && /path/to/job2
Here is my solution:
$ crontab -l
* * * * * cd /patch/to/script; . /patch/to/.profile; overlap.pl process.sh -t Device || process.sh -t Device
$
$
$ cat overlap.pl
#!/usr/bin/env perl
use warnings;
use strict;
my $cmd = join(' ',#ARGV);
my #result = `pgrep -f \"$cmd\"`;
scalar #result > 2 ? exit 0 : exit 1;
EXPLANATION:
this job runs script every minute to check if it works (* * * * *)
cron job is complex, fisrt change directory, load profile so I need to launch script directly from this job not from script that is checking if overlapped
and then check if this particular process with the same parameters is already running (overlap.pl with exact command that I want to check)
if "no", return 0, if "yes", return >0
then there is logical "or" checking result and launch desired script or not
Pay attention to the array length in overlap.pl, you can check it by yourself by doing `ps -elf | grep \"$cmd\" >> /tmp/croncheck`;
You can do that just using cron. You are going to have to add some logic to your script or code to check if the other one is running or not. A total hack would be to have your script check for the exists of a particular file. If it does not exist then you should create this file, perform the backup, then remove it. If the file does exist, do nothing.
That is a hack and only really works because your jobs are spaced so far apart.

Resources