wp-cron it up

CronIf you’ve spent much time mastering *nix servers, you’ve run into cron. I love cron. Cron is a special command that lets you schedule jobs. I use it all the time for various commands I want to run regularly, like the hourly check for new posts in RSS on TinyRSS or RSS2Email, or the nightly backups, or any other thing I want to happen repeatedly. Cron is perfect for this, it runs in the background and it’s always running.

My first thought, when I heard about wp-cron, was that it clearly tapped into cron! If I scheduled a post, it must write a one-time cron job for that. I was wrong. Among other reasons, not everyone has cron on their servers (Windows, I’m looking at you), but more to the point, cron is a bit overkill here. Instead WordPress has a file called wp-cron.php which it calls under special circumstances. Every time you load a page, WordPress checks if there’s anything for WP-Cron to run and, if so, calls wp-cron.php.

Some hosts get a little snippy about that, claiming it overuses resources and ask that you disable cron. One might argue that checking on every pageload is overkill, but realistically, with all the other checks WordPress puts in for comments and changes, that seems a bit off. In the old WordPress days, this actually was a little true. If you have a server getting a lot of traffic, it was possible to accidentally loop multiple calls at the same time. This was fixed quite a bit in WordPress 3.3 with better locking (so things only run once). Multisite was a hassle for a lot of people, but seems to have been sorted out.

StopwatchWe already know that WordPress only calls wp-cron if it needs to, so if you disable it, you have to run that manually (which ironically you could do via a cron job 1). To disable wp-cron, just toss this in your wp-config.php:

define('DISABLE_WP_CRON', true);

Now, remember, you still want to run a ‘cron’ job to fire off anything scheduled, so you have to add in your own cron-job for this, which I actually do! I have cron turned off, and a ‘real’ cron job runs at 5 and 35 past the hour to call wp-cron with a simple command:

curl http://example.com/wp-cron.php

Now since I have multiple domains on this install, I actually have that for every site on my Multisite. After all, wp-cron.php on Ipstenu.org doesn’t run for photos.ipstenu.org and so on. Doing this sped up my site, and put the strain back where I felt it should be. The server.

By the way, wp-cron does more than schedule posts. That’s what checks for plugin, theme and core updates, and you can write code to hook into it to schedule things like backups. Remember before how I said that WP checks to see if there’s anything scheduled? This is a good thing, since if you have your server run a long job (like backing up a 100meg site), you don’t want to wait for that to be done before you page loaded, right?

For most people, on most sites, this is all fine to leave alone and let it run as is. For the rest, if you chose to use cron instead, keep in mind how things are scheduled. Like I set my cron to run and 5 and 35, so I tend to schedule posts for 30 and the hour. That means my posts will go up no later that 5 minutes after. That’s good, but if I use my DreamObjects plugin, the ‘Backup ASAP’ button schedules a backup to run in 60 seconds (so as not to stop you from doing anything else, eh?), which means I’d have to manually go to example.com/wp-cron.php in order to kick it off. Clearly there are issues doing this for a client.

About these ads

Notes:

  1. Read How to Disable WordPress WP-Cron for directions on how to disable and then use real cron.
StudioPress Theme of the Month

Comments

  1. One might argue that checking on every pageload is overkill

    Not really. The check is nothing more than time comparison against the jobs scheduled to run. If any of them have a time-to-run that is less than the current time, then it spawns the wp-cron.php call. Otherwise, it doesn’t.

    In general, I would say the default wp-cron spawning behavior is much lighter on resources than calling it manually from a real cron job, since the default spawning only calls it when it’s actually needed. Using DISABLE_WP_CRON disables this check, but the check is just a few > comparisons. Not really worth the hassle or additional delay, and anyway the check will have to be done whenever you call wp-cron.php manually as well.

    DISABLE_WP_CRON and the likes are there mainly for people who’s hosting systems have issues with local-callbacks.

    • The delay is insignificant for me, since it’s not really a delay at all. A post scheduled for 8am goes off at 8:05am (offset cron) instead of waiting for someone to hit a page. I can use caching as I want (or not) and not worry about calls not being made. I don’t have to worry about multiple hits causing the check to run multiple times. It runs once an hour and I’m content.

      The check is lightweight, and if I could disable the check and call that manually, I’d love to. It would be rather elegant :)

      I love hooking into Cron, but like Drew’s example, you can’t rely on it if you need 1000% absolute times.

  2. I ended up doing something very similar to this with my recent WP Chat Bot experiment.

    I needed to execute a hook hourly at two specific times. Not being able to rely on hits on an unknown site hitting the script manually with server-side cron seemed like the best alternative. I did it using Ben Lobaugh’s post, How to use WP-Cron, for reference.

Half-Elf? Try Half OFF WordPress ebooks!