[wp-hackers] Dealing with WP cron's raciness

Dion Hulse (dd32) wordpress at dd32.id.au
Thu Sep 19 13:19:57 UTC 2013

On 18 September 2013 21:06, David Anderson <david at wordshell.net> wrote:

> 3) Create a few processes that are continually calling wp-cron.php (two or
> more):
> while true; do wget -O - http://localhost/mydevwebsite/**wp-cron.php<http://localhost/mydevwebsite/wp-cron.php>;
> done

I just wanted to point out, that doing this bypasses the major component of
 WP Cron which attempts to allow things to only run once.. doing so you'll
almost be guaranteed to have duplicate events fired.

When WordPress fires off the cron, it creates a locking transient (which
should be pretty reliable when using an external object cache, not awesome,
but still pretty good, when not) which is based on microtime(true) which
includes microseconds: 1379596515.2753798961639404296875
The request is then made via
wp-cron.php?doing_wp_cron=1379596515.2753798961639404296875. If the GET arg
doesn't match exactly what's in the transient, that request doesn't perform
any operations.

In the past (pre-3.6 I believe?), the transient was based on time(), so any
requests made within a 1second timeframe would trigger duplicate cron

It's definitely not foolproof, but it's pretty much as locking-as-possible
that WordPress can achieve in a shared hosting environment at present..
anything that absolutely requires only one process to be running at a time
should definately add something of their own if they don't trust core's

It should also be noted, that if you have a long-running job (like some
backup plugins), and you have a server where someone triggers wp-cron.php
manually with a real cron every 1/2/5minutes, then you'll most likely get
duplicate events running.. simply because your event is only de-queued
AFTER it's run, so if it takes 5 minutes to run, and another request it
made 2 minutes into that window, you'll get two jobs

If you want to test WordPress's cron locks out, instead of using the above
code, do something like this in a stand alone script instead:
<?php include 'wp-load.php'; while(true) { spawn_cron(); } ?>

More information about the wp-hackers mailing list