Cron jobs are used for scheduling tasks to run on the server. They're most commonly used for automating system maintenance or administration. However, they are also relevant to web application development. There are many situations when a web application may need certain tasks to run periodically. Today we are going to explore the fundamentals of cron jobs. Show
DefinitionsFirst, let's familiarize ourselves with the terms related to this subject. "Cron" is a time-based job scheduler in Unix-like operating systems (Linux, FreeBSD, macOS, etc.). And these jobs or tasks are referred to as "cron jobs". There is a cron "daemon" that runs on these systems. A daemon is a program that runs in the background all the time, usually initiated by the system. This cron daemon is responsible for launching these cron jobs on schedule. The schedule resides in a configuration file named "crontab". That's where all the tasks and their timers are listed. Why Use Cron Jobs?Server admins have been using cron jobs for a long time. But since the target audience of this article is web developers, let's look at a few use cases of cron jobs that are relevant in this area:
SyntaxHere is a simple cron job: 1 10 * * * * /usr/bin/php /www/virtual/username/cron.php > /dev/null 2>&1 There are two main parts:
The command itself in this example has three parts:
Timing SyntaxThis is the first part of the cron job string, as mentioned above. It determines how often and when the cron job is going to run. It consists of five parts:
Here is an illustration: AsteriskQuite often, you will see an asterisk ( 18) instead of a number. This represents all possible numbers for that position. For example, an asterisk in the minute position would make it run every minute. We need to look at a few examples to fully understand this syntax. Examples:This cron job will run every minute, all the time: 1 * * * * * [command] This cron job will run at minute zero, every hour (i.e. an hourly cron job): 1 0 * * * * [command] This is also an hourly cron job, but it runs at 15 minutes after the hour instead (i.e. 00:15, 01:15, 02:15, etc.): 1 15 * * * * [command] This will run once a day, at 2:30 am: 1 30 2 * * * [command] This will run once a month, on the second day of the month at midnight (e.g. 2 January at 12:00 am or 2 February at 12:00 am): 1 10 * * * * /usr/bin/php /www/virtual/username/cron.php > /dev/null 2>&11 This will run on Mondays, every hour (i.e. 24 times in one day, but only on Mondays): 1 10 * * * * /usr/bin/php /www/virtual/username/cron.php > /dev/null 2>&13 You can use multiple numbers separated by commas. This will run three times every hour, at minutes 0, 10, and 20: 1 10 * * * * /usr/bin/php /www/virtual/username/cron.php > /dev/null 2>&15 The division operator is also used. This will run 12 times per hour—every 5 minutes: 1 10 * * * * /usr/bin/php /www/virtual/username/cron.php > /dev/null 2>&17 Dash can be used to specify a range. This will run once every hour between 5:00 am and 10:00 am: 1 10 * * * * /usr/bin/php /www/virtual/username/cron.php > /dev/null 2>&19 Also, there is a special keyword that will let you run a cron job every time the server is rebooted: 1 11 Setting Up and Managing Cron JobsThere are a few different ways to create and manage your cron jobs. Control PanelsMany web hosting companies provide control panels for their customers. If you are one of them, you might be able to find a section in your control panel to manage your cron jobs. Editing the CrontabRunning this command will launch vi (text editor) and let you edit the contents of the crontab. If you don't have any crontab files on your system, the command will create one. 1 13 So it would help to be familiar with the basic vi commands as it is quite different than any other text editor you might have worked with. If you would just like to see the existing crontab without editing it, you can run this command: 1 15 To delete the contents of the crontab: 1 17 Loading a FileYou can write all of your cron jobs into a file and then push it into the crontab: 1 19 Be careful because this will overwrite all existing cron jobs with this file's contents, without warning. CommentsYou can add comments followed by the 19 character. 1 * * * * * [command]1 * * * * * [command]2 10 * * * * /usr/bin/php /www/virtual/username/cron.php > /dev/null 2>&1 Setting the EmailAs I mentioned earlier, by default the output from the crons get sent via email, unless you discard them or redirect them to a file. The 30 2 * * * [command]0 setting lets you set or change which email address to send them to: 1 * * * * * [command]5 * * * * * [command]2 * * * * * [command]1 * * * * * [command]8 10 * * * * /usr/bin/php /www/virtual/username/cron.php > /dev/null 2>&1 Using the PHP ParserCGI scripts are executable by default, but PHP scripts are not. They need to run through the PHP parser. That's why we need to put the path to the parser before the path of the script. 1 11 Sometimes, it might be under another location, like /usr/local/bin/php. To find out, you can try running this in the command line: 1 13 Handling the OutputIf you do not handle the output of the cron script, it will send the output as emails to your user account on the server. Discarding OutputIf you put 17 at the end of the cron job command (or any command), the output will be discarded. The closing bracket ( 30 2 * * * [command]2) is used for redirecting output. 30 2 * * * [command]3 is like a black hole for output. Anything that goes there is ignored by the system. This part 30 2 * * * [command]4 causes the STDERR (error) output to be redirected to the STDOUT (normal) output. So that also ends up in the 30 2 * * * [command]3. Outputting to a FileTo store the cron output in a file, use the closing bracket ( 30 2 * * * [command]2) again: 1 15 That will rewrite the output file every time. If you would like to append the output at the end of the file instead of a complete rewrite, use a double closing bracket ( 30 2 * * * [command]7) instead: 1 17 Executable ScriptsNormally, you need to specify the parser at the beginning of the command as we have been doing. But there is actually a way to make your PHP scripts executable from the command line, like a CGI script. You need to add the path to the parser as the first line of the script: 1 19 * * * * * [command]2 0 * * * * [command]1 * * * * * [command]8 0 * * * * [command]3 0 * * * * [command]4 0 * * * * [command]5 0 * * * * [command]6 0 * * * * [command]7 0 * * * * [command]8 0 * * * * [command]9 10 Also make sure to set the proper permissions (like 755) to make the file executable. When you have an executable script, the cron job can be shorter, like this: 1 12 Preventing Cron Job CollisionIn some cases, you may have frequent running cron jobs, and you may not want them to collide if they take longer to run than the frequency itself. For example, you may have a cron job running every minute. Yet, every once in a while, it may take longer than one minute to run. This can cause another instance of the same cron script to start running before the previous one finishes. You can create too many busy processes this way and possibly crash the server if they keep slowing each other down and cause even more processes to be created over time. This problem can be addressed via file locking, and more specifically the non-blocking ( 30 2 * * * [command]8) type of file locks. (If you are not familiar with file locking, I suggest you read about it first.) You can add this code to the cron job script: 1 14 * * * * * [command]2 * * * * * [command]8 17 0 * * * * [command]3 19 0 * * * * [command]5 15 * * * * [command]1 0 * * * * [command]6 15 * * * * [command]3 0 * * * * [command]8 0 * * * * [command]9 15 * * * * [command]6 15 * * * * [command]7 15 * * * * [command]8 15 * * * * [command]9 With regular file locks, the 30 2 * * * [command]9 function call would block the script if there is an existing lock. And it would release once that lock is gone. However, with a non-blocking lock, such as in the code above, the function call does not stop the script, but it immediately returns 10 * * * * /usr/bin/php /www/virtual/username/cron.php > /dev/null 2>&100 if there is an existing lock. So in this case, we can immediately exit the script when we see there is an existing lock, which indicates that another cron job is currently running. Blocking Web Access to Cron JobsWhen you write a cron job in a web scripting language like PHP, you may want to make sure that nobody can execute it by just loading it from their browser. One easy option would be to store these scripts outside of your web folder. However, this may not be practical or preferable for some developers, if they want to keep their cron job scripts right within their web application folders. If you put all of the cron job scripts in a folder, you block access by putting this line in an .htaccess file: 1 11 Or you can also deny access to scripts on an individual basis by putting this line at the beginning: 1 13 This will ensure that, when the script is accessed from the web, it will abort immediately. Cron Job MonitoringSetting cron jobs and assuming they will all work as expected is not a good practice. Wouldn't it be cool to have a tool that monitors your running tasks and ensure that any failing, broken, or delayed cron jobs are discovered promptly? Cron job monitoring allows you to monitor your cron jobs and get ahead of any delays or crashes. A few monitoring tools are available, and the most popular is Cronitor. Cronitor allows you to capture every cron job's status, metric, and output and alerts the relevant person in case of any issue. It even allows you to integrate with popular messaging platforms like Slack, Microsoft Teams, SMS, and email to ensure that failure alerts are delivered on time. ConclusionThank you for reading. Even though cron jobs just seem like a tool just for system admins, they are actually relevant to many kinds of web applications. This post has been updated with contributions from Esther Vaati. Esther is a software developer and writer for Envato Tuts+. |