Quick summary
WooCommerce Action Scheduler jobs get stuck when scheduled work is not triggered on time, a callback fails or workers cannot consume new tasks as quickly as they are created.
- Separate pending, failed and overdue actions before changing cron, PHP-FPM or database settings.
- A growing pending count does not automatically mean that the server needs more CPU; the runner, loopback requests or a slow callback may be the bottleneck.
- WP-CLI provides a more predictable way to inspect and cautiously run the queue. A CLI worker does not use a PHP-FPM web worker unless it makes an HTTP request.
- Do not delete pending or failed actions in bulk. They may represent stock updates, emails, payments or webhooks that still need to run.
Orders are being placed, but scheduled emails are late, stock synchronisation is not completing or webhooks remain in the queue for hours. These are common reasons to investigate WooCommerce Action Scheduler stuck jobs.
The queue can grow while CPU and memory appear normal. The problem may be that nothing is triggering the runner, that a loopback request is blocked or that one callback spends so long waiting for an API or database lock that other work is delayed.
Action Scheduler is a task queue library used by WooCommerce and other WordPress plugins. It lets a plugin schedule work for later instead of performing everything during the original web request. Emails, stock changes, subscription operations, webhooks and external service synchronisation may all use it.
The right fix depends on the failing stage. First determine whether actions are being created, selected and executed, or completed successfully. Shortening a cron interval without making that distinction can increase load without clearing the underlying problem.
How the Action Scheduler queue works
When a plugin needs to send a webhook after an order, for example, it creates an action record. The record includes a hook name, scheduled time, status and retry information. A runner selects actions that are due and executes the PHP callback associated with each hook.
This process has two separate parts. The first is writing tasks to the queue. The second is selecting and running those tasks. If actions are created correctly but the runner does not run, pending records accumulate. If the runner starts but the callback fails, failed records increase instead.
Action Scheduler may be triggered by WordPress cron, requests to the site or WP-CLI, depending on the installation and configuration. WordPress cron is not normally an operating-system scheduler. In many installations, WordPress checks for due events when a visitor request arrives. A low-traffic store can therefore experience delayed scheduled actions even when the web server has spare capacity.
A queue worker started through WP-CLI is a separate command-line PHP process. It does not consume a PHP-FPM web worker unless the process itself makes an HTTP request. This distinction matters: increasing the PHP-FPM child-process limit will not fix a server cron job that never starts.
Example scenario
Assume a store receives most of its traffic during the day and has no server cron configured. Order-related actions are written to the queue, but no new HTTP request arrives overnight to trigger the runner. When the admin area is opened in the morning, some actions run together. In this constructed scenario, the delay comes from the trigger model rather than database pressure.
What queue symptoms tell you
Pending actions keep increasing
If pending actions increase and the oldest scheduled time is in the past, the runner may not be running often enough, may be consuming work too slowly or may be facing a task group that continuously creates new actions.
Look beyond the total count. Check the age of the oldest pending action and the hooks attached to the largest groups. If hundreds of actions belong to one product synchronisation or webhook hook, the issue may be isolated to that integration rather than WooCommerce performance as a whole.
A task that fails and is repeatedly rescheduled can also make the queue grow faster than it is consumed. In that case, increasing worker capacity before examining the error may create more retries without resolving the cause.
Failed actions are multiplying
Failed records show that the runner has at least attempted the callback, but the callback did not finish successfully. The error may mention a remote API response, authentication, a timeout, a PHP exception or a database failure.
Record the hook name, error text and relevant arguments before retrying. Deleting failed actions only hides the evidence and does not prevent the same failure from occurring on the next order.
Emails and webhooks arrive late
Action Scheduler only describes the execution of the scheduled task. It does not by itself guarantee email delivery. An action may complete while the mail server, DNS, recipient policy or application configuration delays or rejects the message.
First establish whether the action ran and whether its callback returned an error. Then inspect the email or webhook delivery layer. For the separate delivery chain, see the guidance on Transactional Email for WordPress and WooCommerce.
The Scheduled Actions screen becomes slow
The Scheduled Actions screen may need to query and paginate a large number of records. A slow admin screen does not necessarily mean that every storefront request is slow.
When the admin interface is under pressure, avoid running large batches from the browser. Use WP-CLI with a small batch size and observe the result. This reduces the chance that a browser timeout leaves you uncertain about what ran.
Diagnose the queue before changing it
Before a data-changing cleanup or retry, take a database backup and confirm that it can be restored. For live stores, choose a maintenance window when stock, order and payment workflows can be observed. Diagnosis does not require deleting actions or disabling the hook that created them.
Start with the Scheduled Actions screen
Open Scheduled Actions in the WooCommerce or WordPress administration area. Review pending, in-progress, complete, failed and canceled statuses separately. These questions provide a useful first classification:
- How far in the past is the oldest pending action scheduled?
- Are pending actions concentrated under one hook or spread across several plugins?
- Do failed actions show the same error or the same external service?
- Are actions completing while new actions are added faster?
- Are repeated actions using the same object, order or product arguments?
Note the hook name and the plugin that provides it before manually running an action. Stock, refund, subscription and webhook actions can have side effects. Running one repeatedly without understanding its retry behaviour may send duplicate notifications or update an external system more than once.
Inspect status and timing with WP-CLI
For this step, you need SSH access, the correct WordPress installation path and a site user with the required file permissions. WP-CLI and Action Scheduler command syntax can vary by installed version, so confirm the available commands before using them. The following commands list actions and show WordPress cron events:
cd /var/www/example.com
wp action-scheduler list --status=pending --per-page=20
wp action-scheduler list --status=failed --per-page=20
wp cron event listThe path is an example; replace it with your WordPress directory. If a command is unavailable, check the Action Scheduler and WP-CLI versions and run the relevant help command before changing plugins or deleting anything.
Compare the scheduled time, hook and group in the pending list. In the failed list, compare the error details. Watch whether a hook creates another action each time it runs. This separates a trigger problem from a callback problem.
Why Action Scheduler jobs get stuck
WP-Cron or server cron is not running
WordPress cron may be disabled. Administrators sometimes set DISABLE_WP_CRON in wp-config.php to avoid relying on visitor traffic. That is reasonable only when an operating-system cron job takes over the work. Without a replacement, scheduled WordPress events and Action Scheduler tasks may stop.
A server cron entry can also fail because it uses the wrong PHP binary, WordPress path, working directory or user permissions. Check the cron output and system logs before shortening the schedule.
If you are replacing visitor-triggered events with a system scheduler, the practical details are covered in Automating Backups, Reports and Maintenance with Cron Jobs. Apply the same diagnostic discipline here: verify the command manually, then verify the scheduled execution.
Loopback or HTTP requests are blocked
A web-based runner may send an internal HTTP request to the same site. A security plugin, basic authentication, WAF, DNS resolution, TLS verification or a server rule can block that loopback request. The admin area may look normal while the runner fails.
Check the loopback warning in WordPress Site Health together with web-server access and error logs. Distinguish enabling a monitoring or runner endpoint from creating a safe access path to it. Enabling an endpoint does not mean leaving it publicly accessible. If access is needed, restrict it with the appropriate method, authentication and network rule.
A callback runs slowly or becomes blocked
A callback may wait for a remote API, update a large product set in one operation or wait for a database lock. A worker handling a batch may then spend most of its time on one action while other due actions wait.
PHP max_execution_time, HTTP timeouts and the remote service response time can all matter. During diagnosis, identify the hook consuming the time before changing several timeout or process settings at once.
New work arrives faster than it is consumed
Stock synchronisation, price updates and marketplace exports may create actions at regular intervals. The runner can be working correctly while the queue still grows because each run completes fewer actions than are created during the same period.
Running cron more often may help in a temporary backlog, but it can also increase database load or hit an external service rate limit. First compare the production rate with the consumption rate.
Database or server capacity limits the runner
Large Action Scheduler tables can make queries and cleanup more expensive. Full disks, inode limits, high I/O wait, limited database connections or PHP process limits can also prevent actions from finishing on time.
Review CPU, memory, disk I/O and database behaviour together. The WooCommerce capacity planning guidance is useful when you need to assess vCPU, RAM, IOPS and database pressure instead of relying on one metric.
Apply a narrow, testable correction
Fix the scheduler trigger first
Before testing a cron change, confirm the site path, PHP version, WordPress user and backup status. If WP-Cron is disabled, ask the system administrator to verify that a real cron job exists and runs as the intended user.
Run due WordPress cron events manually for a limited observation. Because this can run more than one due event, use a maintenance window when side effects are acceptable:
cd /var/www/example.com
wp cron event run --due-nowThis runs WordPress cron events that are due. If your Action Scheduler version uses its runner through WP-Cron, observe whether pending actions begin to move. If the command returns an error, resolve that error instead of repeating the command.
You can also run Action Scheduler directly through WP-CLI when the installed version supports it:
cd /var/www/example.com
wp action-scheduler run --batch-size=20 --batches=1The small batch and single batch are for controlled verification. If your version does not support these options, use wp action-scheduler help run and follow the syntax shown there. Do not start parallel workers until you know which hooks are being executed and what side effects they have.
After the test, check the pending count, the age of the oldest pending action and the failed records. If pending actions decrease but the same errors remain, the trigger problem is largely confirmed and the callback problem still needs attention.
Isolate a failed hook
If the same hook and error appear repeatedly, check the plugin version, API credentials and external service status. Test the change in staging or during a maintenance window before disabling an integration that affects live orders.
If the issue belongs to one integration, correct that integration rather than stopping the entire Action Scheduler queue. For a remote API timeout, inspect retry counts and determine whether the remote system received each request. Also check for idempotency, meaning that repeating the same request does not create an unwanted duplicate effect.
If idempotency is unknown, do not launch a bulk retry for payment, stock or order notifications. First compare the external system with the WooCommerce order state.
Increase consumption carefully
If the runner works but pending actions decline slowly, begin with a small batch and measure the server effect. Observe CPU, memory, disk I/O, database query time and PHP processes. Increase the batch size gradually rather than starting many parallel workers at once.
Web-based runners depend on PHP-FPM child processes. A cron or queue worker running through CLI does not consume the FPM pool; it uses its own PHP process unless it makes an HTTP request. Determine which execution model is in use before changing FPM settings. If normal web traffic is also slow, review PHP-FPM settings separately.
When the issue is database query cost rather than worker count, review indexing and query behaviour instead of adding parallel workers. This is where MySQL indexing and query optimisation for WooCommerce may help with a broader database investigation.
Caution
Do not delete pending or failed records directly with a database query. Action Scheduler tables contain statuses and relationships that plugins expect. Deletion should happen only after you confirm what the action does, why it is no longer needed and how you will recover. Prefer the cleanup method supported by the relevant plugin.
Clean up old completed records safely
The retention period for complete and canceled actions depends on the plugin version and the store’s operational needs. Confirm that the database backup is restorable before changing retention or cleanup behaviour.
Check whether Action Scheduler’s own cleanup process is running and whether its cleanup event appears in cron logs. Cleanup is not a fix for pending or failed actions. Resolve the failure first, then archive or remove only records that are safe to remove.
For order- and stock-related actions, compare the current object state before a bulk operation. If the tables are large, inspect disk space, index use and query times. Optimising a table will not solve an integration that creates new actions every day.
Verify that the correction worked
Check the queue at three points: immediately after the change, during normal traffic and after a complete scheduled cycle. Compare these indicators:
- Is the age of the oldest pending action decreasing?
- Are fewer actions being created than completed?
- Does the same hook and error continue appearing in failed actions?
- Can you verify the email, stock update or webhook result in the relevant system?
- Do web response times, database load and PHP processes remain acceptable while the runner works?
An action marked complete does not always prove that an external system accepted the operation. A webhook may return an HTTP success response while the receiving application rejects the payload. Compare the Action Scheduler status with plugin logs and the response or application record from the external service.
Frequently Asked Questions
Can a plugin create duplicate actions?
Yes. A plugin or integration can schedule the same logical work more than once if its uniqueness or retry handling is incorrect. Compare hook arguments, object IDs and scheduled times before treating every duplicate-looking action as a worker problem.
Does Action Scheduler replace a message broker?
Not necessarily. It is a WordPress task queue used by plugins, while a dedicated message broker is a separate architecture choice. The correct option depends on delivery guarantees, throughput, retry handling and the application design.
Should I run the queue during peak sales hours?
Only if the workload and side effects are understood. Running a small, monitored batch may be appropriate, but large retries can compete with checkout, database operations or external API limits. A maintenance window is safer for uncertain changes.
Can object cache alone fix a growing queue?
Usually not. Caching may reduce some application queries, but it does not repair a missing cron trigger, a failing callback, a blocked loopback request or an integration that keeps producing failed actions.
Actionable checklist
- List pending, failed, complete and canceled actions separately.
- Record the oldest pending time and the most frequent hook.
- Check WP-Cron, server cron and loopback behaviour as separate systems.
- Compare callback errors, external API responses and plugin logs.
- Take a restorable backup before retries, cleanup or other data-changing work.
- Test with a small batch and increase it only while monitoring resources.
- After the change, verify queue age, failure rate and the real email, stock or webhook result.
Your next step should be to record the hook names from the oldest pending and failed actions. If one hook dominates, inspect its plugin callback and integration. If many unrelated actions are waiting, investigate the cron and loopback path first. This approach gives you a targeted correction for WooCommerce Action Scheduler stuck jobs instead of an unverified server-wide setting change.





