Reading Time: 4 minutes
This tutorial is intended to do two things: to expand on the Cron Troubleshooting article
; and to give an overview of a simple scripting concept that uses the creation of a file as a flag to signify something is running. This is primarily useful when you need to run something continuously, but not more than one copy at a time. You can create a file as a flag to check if a job is already running, , and in turn, check for that flag before taking further action.
The direct application of this is when you have a cron job that runs every minute, or every few minutes. With a rapidly repeating cron, if the previous job takes any longer than the scheduled time, these tasks can pile up causing load on the server, or exacerbating other issues. To avoid this, a simple script can be set up in the crontab (in place of the intended cron task). When the cron is run, it only runs the actual task if there is not a competing process already running.
Why Use a Cron Wrapper?
A cron wrapper is used when you have a cron job that needs to run back to back but needs to not step on itself. This is good for tasks that you want to setup to run continuously. Jobs that should be run anywhere between every minute and every five minutes should be utilizing a wrapper like this.
If you do not use a wrapper on a cron job that runs too frequently, you can get multiple jobs running at the same time trying to do the same thing. These competing tasks slow down the whole works. These “stacking cron jobs” can even get so out of hand that it overloads a server and causes the server to stop responding normally.
What is a Cron Wrapper?
The reason this is called a cron wrapper is that it is a script that wraps around the cron job, and checks if another instance of the cron is already running. If there is another copy running, the wrapper will make the cron skip this run, and wait until the next run to check again. There are a few ways that the cron wrappers ensures no overlap.
Process Check Method
One way is to check all the running processes for the user and double checks that there isn’t already another process with the same name or attributes as the one you want to run. This is how Magento’s cron.sh file works, it checks for another instance of cron.php being run as the user, and if there is one running, it exits. This can be complicated to do reliably, and so is not something that we would recommend for just starting out.
A straightforward method is to use what is called a lockfile. The cron wrapper checks if the lockfile (any file with a specific name/location) exists at the start of the run. If the lockfile is missing, the script creates that file and continues. The creation of the lockfile signals the start of the cron job. When the cron job completes the wrapper script then removes the lock file.
So long as the lockfile exists, a new wrapper will not run the rest of the cron job while another one is running. Once the first run completes and the lock is removed another wrapper will be able to create a new lock file again and process normally.
A Wrapper Script Example
To start, we want to create a simple bash script. Within a file we state the script to be interpreted by the program /bin/bash
Then we want to define the name and location of the lockfile we’ll be using as our flag.
# Set lockfile name and location
Next, the script needs to check if that lockfile exists. If it does exist, then another copy of the script is already running, and we should exit the script.
# Check if the lockfile exists
if [[ -f $lockfile ]]; then
# If the lockfile exists quit
Else, if the lockfile does not exist, then we should create a new lock file to signify that we are continuing with the rest of the script. Creating the lockfile also tells any future copies that might be run to hold off until the lockfile is removed. We also want to include the actual job to be run, whether that’s a call to a URL through the web, running a PHP file on the command line, or anything else.
# If the lockfile is missing continue
# Create the lockfile
# Insert cron task here/code>
Once the intended job is run and completes, we want to clean up our lockfile, so that the next run of the cron job knows that the last run completed and everything is ready to go again.
# Cleanup the lockfile
rm -f $lockfile
In the example above, it is convenient to define the lock file
as a variable ($lockfile) so that it can be referenced easily later on. Also if you want to change the location, you only have to change it one place in the script.
This example also uses a “~” in the path to the lock file as a shortcut. This tells the shell to assume the user’s home directory. As such, the full path would look something more like this: /home/username/tmp/cron.lock.
However, by using the “~” you can use copies of the same script for many users on the same server, and not have to modify the full path for each user. The shell will automatically use the home directory for each user when the wrapper script is run.
Putting It All Together (cronwrapper.sh)
You can copy and paste the following into your text editor of choice on your server. You can name it whatever you want, but here are all the parts put together.
if [[ -f $lockfile ]]; then
# Insert cron task here
rm -f $lockfile
This is a very simple example and could be expanded much further. Ideally, you might add a check to ignore a lock file older than an hour and to run a new instance of cron job anyway. This would account for an interrupted job that failed to clean up after itself. Another extension might be to confirm that the previous job completed cleanly,. Or yet another suggestion, would check for errors from the cron job being run and make decisions or send alerts based on those errors. The world is your oyster when it comes to cron wrappers! Take a look at our Liquid Web’s VPS servers,
for tasks like these to run smoothly.