Developers and webmasters use Linux cron jobs to automate tasks on servers. For websites, WordPress offers something that attempts to replicate the Linux cron utility – a PHP file named wp-cron.php.
In terms of versatility and performance, however, this WordPress Cron file is a far cry from the famous and almighty Linux cron utility.
The most obvious issue with WordPress Cron is that unlike regular Linux cron jobs which run at highly precise (and configurable) intervals, WP-Cron gets executed whenever a user visits the site. On every single page load!
True, WP-Cron does not necessarily keep users waiting (even though the cron tasks may sometimes take longer time than it does to load the actual page). The tasks run in the background as separate processes on the server. But the very fact that WP-Cron gets executed on every page load, causes resource issues.
WordPress Cron Issues
Low to medium traffic websites may not have any issues with WordPress Cron. When an event (page load) has already triggered WP-Cron, WordPress locks the cron until execution completes. This helps to prevent multiple “cron jobs” spinning off and looping on the same events. That’s fairly smart.
But some plugins hook into WordPress Cron, and they do their own thing on every page load. With a handful of such plugins on your site, you could quickly start noticing an overall website slow down.
If you run a high-traffic website, chances are that you also use a number of different plugins for automating stuff: like scheduled newsletters, website-to-social media scheduled posts, syncing of stuff, custom update checkers, etc. With even just a few plugins hooking into WP-Cron and doing their own thing on a high traffic website, you could be in for some maintenance headache.
Imagine your site gets hundreds of visits per minute. Your WordPress Cron will run several times per minute, and that takes up server resources – CPU time and memory. And even though each WP-Cron execution may take only 100-500ms, with more traffic and more custom hooks into WP-Cron, you will soon start to have processes loaded in queue for WP-Cron to execute. RAM especially, will take a hit.
The more WP-Cron puts load on your server, the slower your site becomes. And if your site is on shared hosting, you stand the chance of having your site shut down for putting your web host’s servers under stress and using up resources that are meant to be shared among many websites.
Many advanced web hosts now use their own proprietary implementations of Linux cgroups to lock down resources for individual shared hosting users so that no single website could possibly consume all server resources. Other hosts use tools like CloudLinux (a premium OS also based on Linux cgroups) for this purpose. And some of the most modern web hosts are even experimenting with containerized hosting.
With tools like these that prevent a single site from consuming all the server resources on a shared hosting environment, even if your website doesn’t get shut down when you hit your resource ceiling, some features of your site will stop functioning properly and your pages will begin to load at unbearably slow speeds.
CloudLinux (and similar tools) saves the server and other users’ websites on the same shared server. But for your own resource intensive site, you will need to fix your WP-Cron problem by yourself.
Disabling WordPress Cron
One way to fix the problem is to completely disable WP-Cron using this code snippet:
define('DISABLE_WP_CRON', true);
That line of code should be placed in your wp-config.php file.
The obvious downside to this fix is that WordPress Cron will no longer work across the entire site. So stuff like scheduled posts (which is a core WordPress feature) will stop working. Any plugins dependent on WordPress Cron would malfunction, and any features hooked into WordPress Cron, like checking for plugin and theme updates, would fail.
Considering how severe the downsides of DISABLE_WP_CRON could be, I don’t exactly recommend it (by itself) for any live and functional websites. However, I find it quite handy when debugging and troubleshooting resource usage issues.
Replacing WordPress Cron With Linux Cron
If you really want to disable WordPress Cron and still have all your time-based scheduled tasks working properly, you can go ahead and disable WP-Cron using the DISABLE_WP_CRON directive as shown above, AND THEN manually set up your own traditional Linux cron job that runs the wp-cron.php file at preset intervals (instead of on each page load).
Set up your traditional Linux cron job like this:
*/5 * * * * wget -q -O - "http://yourdomain.com/wp-cron.php" > /dev/null 2>&1
Or, if for some reason you are required to run PHP directly, use this:
*/5 * * * * php /home/$USER/public_html/wp-cron.php
Or, use curl like this:
*/5 * * * * curl -vs -o /dev/null http://yourdomain.com/wp-cron.php > /dev/null 2>&1
With WP-Cron disabled inside wp-config.php, this Linux cron job which calls wp-cron.php for you every 5 minutes, effectively replaces WordPress Cron for your website.
With our 5 minutes interval setting above, the total cron executions per day will be 288. Compared to how many times WP-Cron would normally be called daily on a high traffic website, 288 is a nice low number. Of course you can tweak the cron job to use any interval you want.
With your cron job running at intervals, your site should run faster, even though you may have really high traffic and many plugins hooking into WP-Cron.
Replacing WP-Cron With Linux Cron On Multisite
Suppose you have the following domains all connected via WP multisite:
- http://exampleone.com/
- http://exampletwo.com/
- http://examplethree.com/blog/
Solution 1:
Do what we did in the previous section for a regular WordPress site – disable WP-Cron in your wp-config.php file and then create 3 traditional Linux cron jobs. Use one of the same commands above. Just be sure to change the domain name for each new cron job. For each domain/url in your multisite, create a new cron job.
Solution 2:
The beautiful thing about Solution 1 is that you have control over how frequently the cron jobs would run for each of the domains.
But if you have lots of sites in your multisite network, Solution 1 may be too much work. So, create a new file named wp-multisite-cron.php in the root directory of your WordPress installation. Add the following code to it:
<?php require('./wp-load.php'); global $wpdb; $sql = $wpdb->prepare("SELECT domain, path FROM $wpdb->blogs WHERE archived='0' AND deleted ='0' LIMIT 0,300", ''); $blogs = $wpdb->get_results($sql); foreach($blogs as $blog) { $command = "http://" . $blog->domain . ($blog->path ? $blog->path : '/') . 'wp-cron.php'; $ch = curl_init($command); $rc = curl_setopt($ch, CURLOPT_RETURNTRANSFER, FALSE); $rc = curl_exec($ch); curl_close($ch); } ?>
Now, you can trigger the above file you just created using a Linux cron job like this:
*/5 * * * * wget -q -O - "http://yourdomain.com/wp-multisite-cron.php" > /dev/null 2>&1
Again, you can tweak the command above to set your preferred interval at which it will run.
Throttling WordPress Cron
If you don’t want to go the route of replacing WP-Cron with a pure Linux cron job, you may want to consider “throttling” WordPress Cron.
WordPress 3.3 introduced the WP_CRON_LOCK_TIMEOUT constant which defines a period of time in which only one cron job will be fired.
Define this constant inside your wp-config.php file like this:
define('WP_CRON_LOCK_TIMEOUT', 5400);
In the above example, I have instructed the site to only fire one WordPress Cron job every 5400 seconds (90 minutes) no matter how many user visits and page loads may be happening. Of course, 5400 seconds is just an arbitrary number and you should replace it with a value you’re comfortable with.
This method is my preferred way of dealing with the WordPress Cron issue. It is a really simple tweak and achieves just as much as a traditional Linux cron job would (for this particular scenario). The fact that this is an officially supported WordPress technique is extra icing on the cake.
I have a cloud account on Siteground with over 100 sites. How would you set up the crons in that situation?