Skip to content
PBPrathamesh Basagare

2 min readWordPress

SAMPLE

WP-Cron vs Action Scheduler: when scheduled jobs need a real queue

WP-Cron only runs when someone visits your site, and it fails silently. Here's when that's fine, when it isn't, and how Action Scheduler fixes it.

WP-Cron is not cron. It's a check that runs on page load: when a visitor arrives, WordPress looks for overdue events and fires them. That one design decision explains most "my scheduled task didn't run" bugs.

Where WP-Cron breaks down#

  • Low traffic means late jobs. No visitors, no execution. A renewal reminder due at 9:00 might run at 14:30.
  • High traffic means overlapping runs. Several requests can pick up the same event before it's marked done.
  • Failures are invisible. If a callback throws, there's no retry and no record.
php
// Classic WP-Cron: fine for "clear a transient once a day".
if ( ! wp_next_scheduled( 'myplugin_daily_cleanup' ) ) {
    wp_schedule_event( time(), 'daily', 'myplugin_daily_cleanup' );
}
add_action( 'myplugin_daily_cleanup', 'myplugin_cleanup_expired_tokens' );

Action Scheduler: a queue with a paper trail#

Action Scheduler, the library WooCommerce uses, stores every job as a database row with a status: pending, in-progress, complete, failed. You can see what ran, what failed and why, under Tools → Scheduled Actions.

php
// One-off background job: runs as soon as possible, off the request.
as_enqueue_async_action( 'myplugin_sync_order', array( 'order_id' => $order_id ), 'myplugin' );

// Recurring job, guarded so it's only registered once.
if ( false === as_has_scheduled_action( 'myplugin_hourly_sync', array(), 'myplugin' ) ) {
    as_schedule_recurring_action( time(), HOUR_IN_SECONDS, 'myplugin_hourly_sync', array(), 'myplugin' );
}

Trigger the queue from a real cron#

On anything that matters, stop relying on visitors. Disable the page-load trigger and run due events from the server's crontab:

php
// wp-config.php
define( 'DISABLE_WP_CRON', true );
bash
# crontab -e: run due events every minute with WP-CLI
* * * * * cd /var/www/site && wp cron event run --due-now --quiet

Rule of thumb#

JobUse
Housekeeping that can run lateWP-Cron
Anything touching money, email or third-party APIsAction Scheduler
Large batches (imports, syncs)Action Scheduler, chunked into small jobs
#wordpress#background-jobs#action-scheduler
Related case studyStripe Elements checkout for a membership plugin