Skip to main content

Running the WordPress Cron via CLI

In this lesson you will replace the default WordPress cron system, which relies on HTTP requests, with a more reliable and isolated system cron job that runs through WP-CLI. You will prevent race conditions using filesystem locking, and learn how to find and eliminate long-running or stuck jobs.

WordPress Cron

WordPress has a time-based task scheduling system called WP-Cron. This pseudo-cron system is used internally by WordPress for many things, including fetching core, plugin and theme updates, publishing scheduled posts, and various health and cleanup routines. It is also often used by third-party plugins.

The default method of operation is using HTTP. On a page load, WordPress checks to see if a cron task needs to be run, and spawns a remote HTTP request to itself, without waiting for the result.

There are many problems with this approach:

  • Execution relies on traffic. No traffic = no execution.
  • Execution hogs a PHP worker for the full duration of the execution.
  • HTTP timeout and memory limits may cause execution to fail.
  • Race conditions on high-traffic sites.

For these and some other reasons, it is generally recommended to run the WordPress cron system by using an actual system task scheduler, as well as the CLI context.

WP-CLI Cron

You can invoke the WordPress cron using WP-CLI:

wp cron event run --due-now

This runs all the tasks that are due now, using a CLI context, which typically means no execution time limit and often a larger memory limit. It also runs in a truly background fashion as a completely separate process, meaning it will not consume any PHP pool resources and will run even if PHP-FPM is under heavy load or down.

We can use that with our system cron and run it every minute. However, some tasks may take well over a minute to complete, and launching a second cron run may interfere with the unfinished run and cause race conditions. To avoid these race conditions, we need to:

  • Disable the standard HTTP method of running the WordPress cron.
  • Ensure only one CLI cron is running at any given time.

The first issue can be addressed via a constant in wp-config.php. You can add it manually, or you can use WP-CLI to add it:

wp config set DISABLE_WP_CRON true --raw

The second issue is slightly trickier. My favorite way to solve this is through the Linux flock program, which allows us to use the filesystem for locks. For example:

flock -n /sites/uncached.org/wp-cron.lock \
    wp --path=/sites/uncached.org/public_html \
    cron event run --due-now

This will first attempt to acquire a lock on the wp-cron.lock file, and will run the second part of the command only if successful. If the lock fails, it will simply exit.

System Crontab

We already made a crontab file earlier in /config/misc/crontab for our automatic WP-CLI updates. Let's invoke our WordPress cron by adding a new entry there. Unfortunately it has to be a single line:

This article is for premium members only. One-time payment of $96 unlocks lifetime access to all existing and future content on wpshell.com, and many other perks.