WordPress uses a transient called doing_cron as a simple mutex preventing two cron processes from running in parallel. When a process starts it sets the value to the current time; when it finishes it deletes the transient. If the process is interrupted, the lock remains and everything freezes.
Why this matters
WordPress's cron code checks doing_cron before each run. If the transient exists and its value is younger than WP_CRON_LOCK_TIMEOUT seconds (default 60), WordPress assumes another worker is currently running and skips. That is correct under normal conditions; but if a cron run is killed mid-execution (PHP fatal, OOM, PHP timeout, PHP-FPM restart) the transient can be left behind with an option_value that is never cleaned up. Every subsequent cron request assumes work is in progress and skips. The result: backups, syncs, scheduled post publishing, emails - everything simply stops. And it is not always obvious - there is no error on screen, just silence in the background.
How to detect
Check the transient via WP-CLI:
wp transient get doing_cronIf it returns a timestamp far older than 60 seconds (an hour ago, a day ago) it is stuck. SQL alternative:
SELECT option_name, option_value FROM wp_options WHERE option_name LIKE '%doing_cron%';wp cron event list showing every hook with a negative next_run_relative is also an indirect sign.
How to fix
- The recommended path:
wp transient delete doing_cron. This also clears the timeout entry. - SQL alternative:
DELETE FROM wp_options WHERE option_name IN ('_transient_doing_cron', '_transient_timeout_doing_cron'); - UI alternative: install the free Transients Manager, search for
doing_cronand click Delete. - After deletion enable
WP_DEBUGandWP_DEBUG_LOGinwp-config.phpand wait. The root cause - the fatal that caused the lock - will appear indebug.log. - Fix the offending code or remove the plugin. For third-party plugins file an upstream issue.
- If it recurs frequently, switch to system cron (see wp_cron_status). This removes the dependency on a forgotten lock.
Common mistakes
- Repeatedly clearing without investigating: simply deleting the transient each time is symptomatic, not curative. The problem will return.
- Lowering WP_CRON_LOCK_TIMEOUT too far: this causes two parallel workers to fight over the same task. The default (60) is fine.
- Blaming cron when PHP-FPM is the real cause: OOM errors invite suspicion of WP-Cron, but the actual issue is PHP memory exhaustion. Raise
memory_limitinwp-config.php. - Skipping verification: deletion can succeed only for the lock to reappear within five minutes if the underlying issue persists. Re-check.
Verifying the fix
Run wp cron event run --due-now - overdue events should fire. Run wp transient get doing_cron - should be empty or fresh. Wait 10-30 minutes and verify a backup, an email or a scheduled post completes at the expected moment. RankPlus will return to green.
doing_cron getting stuck several times a week, it is almost always Action Scheduler from WooCommerce dying mid-batch. Clear stuck actions with wp action-scheduler clean and raise memory_limit to at least 512M.