Today I tried to debug a WordPress cron task that a plugin was scheduling, was due to trigger, but would not run. I wasn’t sure whether my action callback was registered correctly, or encountering an error during execution, or whether the internal cron process was not working correctly.

Every WordPress request can potentially trigger a cron job, if one is due to run. When manually trying to trigger a job to run by executing wp-cron.php with a direct request, you may find not every request will execute your job despite being due to run.

In the course of debugging, you may find yourself trying to test your code frequently. If you’re trying to trigger wp-cron too frequently, its locking mechanism will step in, even when a job is due to run and other requests are done processing.

Inspecting the source code at wp-includes/cron.php, you’ll find the following lock code:

// don't run if another process is currently running it or more than once every 60 sec.
if ( $lock + WP_CRON_LOCK_TIMEOUT > $gmt_time )
	return;

As the comment indicates, cron jobs are prevented from running with a frequency exceeding once per minute by default.

That is due to the constant WP_CRON_LOCK_TIMEOUT, and reinforced by looking at its definition in wp-includes/default-constants.php:

if ( !defined( 'WP_CRON_LOCK_TIMEOUT' ) )
	define('WP_CRON_LOCK_TIMEOUT', 60);  // In seconds

If you want to define a custom wp-cron frequency with sub-minute resolution, you’ll probably want to disable WordPress’s internal cron triggering mechanism and use your true system cron, setting the DISABLE_WP_CRON constant to false in your wp-config.php file.

However, multiple unrelated tasks could be due at slightly different times that would not be allowed to trigger within a minute of one another by separate pageviews (something you probably don’t care about), or more likely, you want to be able to debug your cron task frequently while in development.

In this case, you can reduce your WP_CRON_LOCK_TIMEOUT constant value to allow your jobs to run multiple times in a short span of time without waiting for the extended lock to release.

Using these and other methods, I was able to debug a development-specific bug where my site’s home_url was on a domain mapped in my workstation’s hosts file, but not on the machine the development copy of WordPress itself was installed. When it tried to spawn a separate request to itself to automatically run its cron jobs, the request timed out because its home_url was not found!

When debugging in WordPress in general, don’t forget to utilize WP_DEBUG as well!