utahcreates

WordPress does its chores while your visitors wait

And the worst part isn’t the waiting. It’s that when it fails, it says it worked.

The thing most people don’t know

WordPress has a scheduler. It sends your emails, publishes your scheduled posts, cleans out expired data, checks for plugin updates. Reasonably, you might assume something on the server wakes up every few minutes and runs it.

Nothing does. WordPress has no clock of its own.

Instead, when somebody visits your site, WordPress checks whether any chores are due — and if they are, it does them during that visit. The visitor’s page load is the timer. They are standing at the door while the tidying happens.

Two consequences fall straight out of that:

The failure that taught me the most

WordPress ships a mechanism to move this work into a separate background request, and plugins build on it. While testing my own, I hit a failure that is worth describing precisely, because it is the kind that survives for years.

The background request was being fired. It returned HTTP 200. The plugin recorded a successful spawn. The dashboard showed green.

And nothing ran.

The mechanism works by passing a key with the request, which wp-cron.php compares — strictly — against a value WordPress stored earlier. My code sent a key that was never stored to compare against. So wp-cron.php did exactly what it should: it decided this request was not legitimate, declined to process anything, and returned successfully.

A 200 response meant “I heard you”, and I had read it as “I did it”. Every scheduled task on that site was quietly not happening, and every piece of instrumentation said things were fine.

How to actually check, on your own site

Don’t trust a plugin’s status panel, including mine. Use a canary:

  1. Schedule a one-off event a couple of minutes out, whose handler writes a row somewhere — a timestamp, the process ID, and whether DOING_CRON was set.
  2. Wait past the scheduled time without visiting the site.
  3. Read the row back with a direct, uncached query.

Three outcomes, and each tells you something different. No row means nothing is running the scheduler at all. A row whose process ID matches your own page request means cron is running inside visitor page loads. A row from a different process, written without you visiting, means background execution genuinely works.

That third case is the only one that should count as “working”, and it is the only one you can’t infer from a green tick.

What to do about it

The fix that needs no plugin at all: turn WordPress’s built-in behaviour off with define( 'DISABLE_WP_CRON', true ); in wp-config.php, and have your host’s scheduler call wp-cron.php on a real timetable. Every decent host has a cron panel. This is free, boring, and correct.

What that alone doesn’t give you is ordering. Once several jobs are due at once, a housekeeping task and a checkout-related task compete, and the scheduler has no opinion about which matters. That gap — priorities, locking, and knowing when a failure is real — is the part worth building software for, and it is what SwiftQueue exists to do.

The part I keep re-learning

This bug was not findable by reading the code, and I had read that code many times. It needed a live WordPress install, a canary, and a willingness to distrust my own success message.

Four of the six real bugs in that plugin were like this: features that had never worked on any site, sitting behind interfaces that said they had. Now the rule is simply that a feature is not done when the code looks right — it is done when something outside the code has confirmed it.

← More field notes See SwiftQueue