WooCommerce Slow? Fix a Bloated Action Scheduler Queue
If your WooCommerce store has gotten slower over the past few months — wp-admin drags, checkout lags, and your host keeps flagging high CPU — the culprit isn't always your theme or a rogue plugin. Very often it's a bloated Action Scheduler queue quietly grinding your database to a halt.
What Action Scheduler Actually Does
Action Scheduler is a background job library bundled with WooCommerce since version 3.0. It's what runs things like order emails, subscription renewals, stock sync, webhook deliveries, and abandoned-cart follow-ups without making the customer wait for them in real time. Plugins beyond WooCommerce use it too — Jetpack, WP All Import, and most subscription or CRM-sync plugins queue jobs through the same system.
Every job lives as a row in one of four custom tables: wp_actionscheduler_actions, wp_actionscheduler_logs, wp_actionscheduler_groups, and wp_actionscheduler_claims. Under normal conditions these stay small because completed actions get purged automatically after 30 days. When that cleanup stops happening, the tables just keep growing.
Symptom: How to Tell This Is Your Problem
- wp-admin is slow everywhere, not just on WooCommerce screens
- WooCommerce > Status > Scheduled Actions shows thousands of actions stuck as "pending" or "failed"
- Your host's MySQL slow-query log is full of queries against
wp_actionscheduler_actions - On shared cPanel hosting, you're hitting LVE resource limits (CPU/entry process faults) even though traffic hasn't grown
- Performance briefly improves after a server restart, then degrades again over hours
Confirm It From the Database
Open phpMyAdmin (or connect via SSH) and run:
SELECT status, COUNT(*) AS total
FROM wp_actionscheduler_actions
GROUP BY status
ORDER BY total DESC;
A few hundred "pending" rows is normal on an active store. Tens of thousands — especially "failed" or "pending" rows dated weeks back — means the queue has stopped draining.
Cause: Why the Queue Piles Up
1. WP-Cron Isn't Actually Firing
WordPress's built-in cron isn't a real cron job — it fires on page visits. Low-traffic stores, or sites where DISABLE_WP_CRON was set to true without a real replacement, simply never trigger the runner. Actions queue up and nothing processes them.
2. A Plugin Is Scheduling Faster Than It Can Process
Subscription renewals, abandoned-cart emails, or a webhook integration that retries a failing API call can enqueue new actions faster than the runner clears old ones — especially if that third-party API has been down for days and nobody noticed.
3. Failed Actions Retry Indefinitely
When a scheduled action throws an error (a payment gateway timeout, an expired API key), Action Scheduler retries with backoff but keeps the failed log entries. Over months, a single flaky integration can leave tens of thousands of dead rows behind.
4. The Cleanup Job Itself Is Stuck
Action Scheduler purges old completed actions using — ironically — a scheduled action of its own. If the runner has already stalled, cleanup never fires either, and the tables just keep growing unchecked.
Fix: Clear the Queue and Get It Moving Again
Step 1 — Get WP-CLI Access
Use SSH, or the Terminal app in cPanel if SSH isn't enabled on your plan. Confirm WooCommerce's CLI commands are available:
wp action-scheduler action list --status=pending --per-page=0 --field=action_id | wc -l
wp action-scheduler action list --status=failed --per-page=0 --field=action_id | wc -l
Step 2 — Find Which Hook Is Actually Responsible
Don't clear the queue blind — find out what's flooding it first, or you'll be back here in a month:
SELECT hook, COUNT(*) AS total
FROM wp_actionscheduler_actions
WHERE status = 'failed'
GROUP BY hook
ORDER BY total DESC
LIMIT 10;
This almost always points straight at the offending plugin or integration.
Step 3 — Clear the Backlog
For a few hundred stuck actions, the UI is fine: go to WooCommerce > Status > Scheduled Actions, filter by status, and bulk-cancel. For tens of thousands of rows, the admin screen will time out — use WP-CLI instead:
wp action-scheduler action delete --status=failed --hook=<offending_hook_name>
wp action-scheduler action delete --status=pending --hook=<offending_hook_name>
Take a database backup first. If a plugin turns out to be genuinely broken, deleting its queued retries is safe — it isn't going to succeed on attempt 40,000 either.
Step 4 — Fix Why the Runner Stalled
Stop relying on visit-triggered pseudo-cron. Add this to wp-config.php:
define( 'DISABLE_WP_CRON', true );
Then add a real system cron job in cPanel's Cron Jobs tool to run every 5 minutes:
*/5 * * * * wget -q -O - "https://yourdomain.com/wp-cron.php?doing_wp_cron" >/dev/null 2>&1
If WP-CLI is available on your plan, this is lighter on resources than a wget hit:
*/5 * * * * cd /home/username/public_html && wp cron event run --due-now --quiet
Step 5 — Raise the Batch Size for High-Volume Stores
If your store genuinely processes thousands of orders and the default runner can't keep up, increase concurrency in functions.php:
add_filter( 'action_scheduler_queue_runner_batch_size', function() {
return 50; // default is 25
});
add_filter( 'action_scheduler_queue_runner_concurrent_batches', function() {
return 3; // default is 1
});
Only raise this on a VPS with headroom — on shared hosting it just moves the CPU spike somewhere else.
Prevention: Keep the Queue From Bloating Again
| Practice | Why It Matters |
|---|---|
| Check Scheduled Actions weekly | Catches a runaway integration before it reaches 50,000 rows |
| Audit new plugins/integrations on install | Payment, shipping, and CRM-sync plugins are the most common offenders |
| Alert on webhook/API failures fast | A silently-dead third-party API is the #1 cause of failed-action pileups |
Run OPTIMIZE TABLE after a big cleanup | InnoDB doesn't reclaim disk space from deletes on its own |
| Keep WooCommerce updated | Action Scheduler's own performance has improved significantly since the 3.x rewrite |
OPTIMIZE TABLE wp_actionscheduler_actions, wp_actionscheduler_logs;
If you're on Getwebup's managed cPanel hosting and aren't sure whether SSH or WP-CLI is enabled on your plan, our support team can run this cleanup for you directly — just open a ticket with your domain name.
Frequently asked questions
Is it safe to delete pending or failed Action Scheduler actions?
Yes, once you've identified the hook causing the pileup. Deleting a queued retry for a plugin that's genuinely broken doesn't lose data — it just stops WooCommerce from trying the same failing job again. Back up your database first if you're deleting tens of thousands of rows at once.
Why does WooCommerce use Action Scheduler instead of running everything on WP-Cron directly?
WP-Cron alone can't handle large batches reliably — it's tied to page visits and has no concept of retries, logging, or concurrency. Action Scheduler adds its own database-backed queue on top of WP-Cron (or a real system cron) so background jobs like order emails and renewals actually complete, even at scale.
How often should the wp_actionscheduler tables be cleaned up?
Action Scheduler purges completed actions after 30 days automatically, as long as its own cron runner is firing. If you've had to manually clear a backlog once, check the Scheduled Actions screen weekly for the next month to make sure it doesn't recur.
Can I just disable Action Scheduler to stop the slowdown?
No — WooCommerce depends on it for core functionality like processing orders and renewing subscriptions. Disabling it will break checkout flows, not fix your performance problem. Fix the stalled cron runner and clear the backlog instead.