Managing Duplicate Cron Job When Executing Scripts
If during a set of times, you've observed a specific pattern on your Linux device triggering an alarm for a high CPU/memory usage, it is recommended to analyze the set of processes that where running at the time of the alarm.
During the analysis you might find that an specific process or script is running multiple instances simultaneously due to a duplicate call on a scheduled process (which was set up using cron jobs).
To prevent this from happening, you can use two alternatives:
Setting up a lock file
Within the script, implement a procedure that verifies wether a file exists. If it doesn't, then the script will create it and continue executing as expected. If the file is not required once the script's complete, you can then delete it to ensure the next run of the job will not consider it as "in use".
Setting up a PID file in BASH
Similar to the above-mentioned method, using a Process ID (PID) file relies on reading a file, with the difference that within this file, the PID of the running instance is placed, this will allow to validate that the process if the process is running, while the lock file only verifies that the script started running, disregarding if it's still running, or if it was paused/terminated before the file got removed.
Steps to set this up:
Through the below code snippet, you can see a sample of the code that you would implement within your script.
The text that starts with a pound symbol (#) is a comment within the code, so it can be removed on the final implementation.
NOTE: Be aware that you first need to test if the script fits your needs. Do not assume it may work in the first try. Modifications may be needed.
#!/bin/bash
LOCKFILE="/var/apps/testscript.lock"
# Create/open the lock file and assign file descriptor 200
exec 200>"$LOCKFILE" || {
echo "ERROR: Could not open lock file: $LOCKFILE"
exit 1
}
# Try to obtain the lock without waiting
if ! flock -n 200; then
echo "Job is already running"
exit 1
fi
echo "Job started with PID $$"
# ==========================================================
# Original script code starts here
# ==========================================================
# Example:
# /usr/bin/some-command
# /usr/bin/another-command
# ==========================================================
# Original script code ends here
# ==========================================================
exit 0
Other solutions
Additional to the two above alternatives, there are different utilities that you can implement.
Flock
The flock command is a utility installed on newer Linux distributions that manages locks from shell scripts
You can refer to the official documentation at the below URL to understand more about it's usage:
-
https://manpages.ubuntu.com/manpages/xenial/man1/flock.1.html
The useful thing about flock is that the file lock will be kept in place until the original process completes, at that point flock will release the file lock. This is true whether the process completes successfully or unsuccessfully.
Solo
Solo is a Perl script that binds the execution of the script to a network port instead of a file,
You can refer to the official website to get more information:
-
Similar to other implementations, this will create a lock that will only release after the assigned script completes:
$ ./solo -port=1234 /var/tmp/script.sh & 1234
$ ./solo -port=1234 /var/tmp/script.sh
solo(1234): Address already in useThe advantage of binding a port instead of a file, is that a port cannot be deleted. Which with other implementations, would 'release' the existing lock, allowing duplicate instances of a job.
Additional notes
While the above utilities and practices prevent running duplicate jobs, it is important to monitor the way your cronjobs interact as to avoid overlapping jobs or excesive use of resources that could hinder the performance of our device and operations.
Related articles
Use the Feedback tab to make any comments or ask questions. You can also start a conversation with us.
Updated 14 days ago
