Offset Crons with Sleep and Flock together - cron

I run several cron jobs every minute - I use flock to prevent overlapping as a couple of the scripts may run for over minute:
* * * * * flock -n /path/to/lock-process-1.txt php /path/to/process-1.php
* * * * * flock -n /path/to/lock-process-2.txt php /path/to/process-2.php
However, all the processes run at the same time (and most of the processes only take a few seconds). So I'd like to stagger the crons so that they are ten seconds apart. I have read elsewhere that this can be done with sleep (from this post):
* * * * * sleep 10;curl http://www.google.com/
My question is: can I use sleep alongside flock and if so, where do I add the sleep 10;

I went ahead and tested this and it is OK to have sleep before flock:
* * * * * sleep 10; flock -n /path/to/lock-process-2.txt php /path/to/process-2.php

Related

How to schedule multiple CronJobs using bash without conflicting each other?

I have 4 Jobs, which run at different intervals. How can I prevent them from conflicting each other? Job 2,3,4 can only be run one at a time. Any new job invocation must wait for old completion before beginning.
0 9,11,14 * * 1-5 /bin/bash /home/userName/Desktop/Auto/job_1.sh
0 8-17 * * 1-5 /bin/bash /home/userName/Desktop/Auto/job_2.sh
*/6 * * * * /bin/bash /home/userName/Desktop/Auto/job_3.sh
*/20 * * * * /bin/bash /home/userName/Desktop/Auto/job_4.sh
Any help is much appreciated. Thanks!
I would look into using flock.
You have to install util-linux to get flock.
It has lots of options like timeout, etc.
Your crontab could look something like this:
0 9,11,14 * * 1-5 flock -x /tmp/cronjobs.lock -c '/bin/bash /home/userName/Desktop/Auto/job_1.sh'
0 8-17 * * 1-5 flock -x /tmp/cronjobs.lock -c '/bin/bash /home/userName/Desktop/Auto/job_2.sh'
*/6 * * * * flock -x /tmp/cronjobs.lock -c '/bin/bash /home/userName/Desktop/Auto/job_3.sh'
*/20 * * * * flock -x /tmp/cronjobs.lock -c '/bin/bash /home/userName/Desktop/Auto/job_4.sh'
The syntax for flock is:
flock -x <lockfile> -c '<command>'
The lockfile is a file that is locked on your machine. Each new command will check to see if that file is locked by a previous command. Once that previous command finishes, it releases the lock and the next command can run, taking out a new lock.
Using the -w <seconds> command you can tell flock the time in seconds to wait while trying to take out a lock on the file before the command fails and does not run.
For instance, the following would wait 3 minutes for previous cron job to finish. If it did not finish in that time then the command below would not run.
*/20 * * * * flock -w 180 -x /tmp/cronjobs.lock -c '/bin/bash /home/userName/Desktop/Auto/job_4.sh'

Crontab every 5 minutes, but not on 5,10,15, etc

Some of my sites need regular crontabs, I use this to start a cronjob every 5 minutes "*/5 * * * *".
The crontabs are small, light, but there are starting to be several sites that need them, and starting them all together, it starts not being a very good idea.
With this "*/5" the cron starts at 5, 10, 15 20, etc... is it possible to make it start at, for example 8,13,18,23, etc?
Vixie cron accepts steps in a range (thanks Keith Thompson), so you can do
3-58/5 * * * * my_command
With other versions of cron, this may not be supported and you'd just have to do
3,8,13,18,23,28,33,38,43,48,53,58 * * * * my_command
Another option is something like
*/5 * * * * sleep 3m ; my_command
This could be adapted to sleep for a random time, thus further spreading out the jobs. For instance, you could do
*/5 * * * * /bin/bash -c 'sleep $((RANDOM/(32767/180))) ; my_command'
or use SHELL = /bin/bash further up in your crontab to make the /bin/bash -c unnecessary, if you're okay with using bash to run all the other cron jobs following the SHELL = line. $RANDOM in bash expands to a random integer between 0 and 32767, so this gets you a delay of up to 180 seconds.

Crontab bad minute

I am trying to add multiple cron tasks in crontab.
Step 1
crontab -e
Step 2
* * * * * php /home/vagrant/project/artisan do:task 1 >> /dev/null 2>&1
1/3 * * * * php /home/vagrant/project/artisan do:task 2 >> /dev/null 2>&1
Step 3 - Save
crontab":1: bad minute
if I remove the 1/3 to become
3 * * * * php /home/vagrant/project/artisan do:task 2 >> /dev/null 2>&1
it saves fine but I need the offset.
Any help would be appreciated.
Figured it out.
I am using Laravel and i the task manager it parses
1/3 * * * *
perfectly fine but when using crontab I must use this format.
1-59/3 * * * *
Phew!!!
Schoolboy error!!! :-)
For others that might run into this issue, it can be either of the following problems:
The error "crontab":1: bad minute" actually mentions the line where the problem is: Here the error is with line # 1
Check if the hard disk is completely filled. The crontab cannot write the changes even in that case. Happens often !

How to sleep 10 seconds before running a linux command?

Simple question: I want to run a cron operation every minute at the 10th second (for example at 2:00:10 PM). The cron operation runs a curl command to download a website page. How can I run a cron operation to do that?
Current crontab setting:
* * * * * curl http://www.google.com/
* * * * * sleep 10;curl http://www.google.com/

Cron jobs -- to run every 5 seconds

I want to create cron job that runs a script every 5 seconds. Seeing that cron jobs only allows increments of minutes 0-59 and so on.
I thought to create another script that calls my original script written below.
#!/bin/bash
while true
do
# script in the same directory as this script. is this correct?
bash makemehappy.sh
sleep 1
done
I now, need to know how to run this script every time i boot my computer and for it to start itself if it isn't running for some reason.
I am also aware that running this script every minute wouldn't be a good thing. :)
if there is an easier way to run a script every 5 seconds please advise.
Please and thank you.
I wouldn't use cron for this. I would use that bash script (use an absolute path, unless you want it to be portable and know that the directory structure will be preserved).
Instead, I would just sleep 5, just like you did (only 5 seconds instead of 1).
As far as starting it with your system, that depends on the system. On (some) Linux distros, there's a file called /etc/rc.local in which you can add scripts to run when the system starts. Well... I shouldn't be so general, the distros that I have used have this. If you're running Ubuntu, there is no longer an inittab, they use upstart, btw.
So if you have an endless loop and an entry in /etc/rc.local, then you should be golden for it to run endlessly (or until it encounters a problem and exits).
Try using anacron or, better yet, an init script to start when the computer starts.
If you want the script to "restart itself", you'll need to run something every few minutes to check the original is still running. This can be done in inittab (/etc/inittab) or, on Ubuntu, /etc/event.d. Try man 5 inittab, looking at the 'respawn' option.
Some crons have an #reboot time specifier (this covers all the time and date fields). If yours does, you can use that. If this is a "system" service (rather than something running for yourself), the other solutions here are probably better.
Init scripts are fine at boot, but don't detect if a process fails and has to be restarted. supervisord does a great job of detecting failed processes and restarting them. I'd recommend a script with a 5-second loop like #Tim described, but wrap supervisord around it to make sure it keeps running.
As explained in detail in my answer to a similar question, you can use SystemD timer units with whatever schedule that you want - down to a theoretical 1 nanosecond schedule with no sleep kludges
Quick overview:
Setup a SystemD service to run what you want - this can be as simple as:
/home/myusuf3/.config/systemd/user/makemehappy.service
[Unit]
Description=Make me happy
[Service]
ExecStart=/home/myusuf3/.local/bin/makemehappy.sh
Setup a SystemD timer with the schedule that you want, as documented in man systemd.timer:
/home/myusuf3/.config/systemd/user/makemehappy.timer
[Unit]
Description=Schedule to make me happy
[Timer]
OnBootSec=5
OnUnitActiveSec=5
AccuracySec=1
Enable and start the timer:
:
systemctl --user daemon-reload
systemctl --user enable makemehappy.timer
systemctl --user start makemehappy.timer
(after you enable it, it will autostart every time you start the computer, but you probably want to start it now anyway).
To answer the question in the title, this is how to run a cronjob every 5 seconds :
* * * * * /path/to/script.sh
* * * * * sleep 5 && /path/to/script.sh
* * * * * sleep 10 && /path/to/script.sh
* * * * * sleep 15 && /path/to/script.sh
* * * * * sleep 20 && /path/to/script.sh
* * * * * sleep 25 && /path/to/script.sh
* * * * * sleep 30 && /path/to/script.sh
* * * * * sleep 35 && /path/to/script.sh
* * * * * sleep 40 && /path/to/script.sh
* * * * * sleep 45 && /path/to/script.sh
* * * * * sleep 50 && /path/to/script.sh
* * * * * sleep 55 && /path/to/script.sh
It's not beautiful, but this solution comes with no extra tools nor dependencies. So if you have working cron jobs, this should work right away.

Resources