Skip to content

action_scheduler_use_async_request_runner filter not respected — async runner bypasses filter and floods MySQL #3874

Description

@nelullc

🔎 Isolate the bug

  • I have confirmed this occurs in the most recent version of WordPress, WooCommerce, and Meta for WooCommerce.
  • I have confirmed this occurs when only WooCommerce and Meta for WooCommerce are active and when using a default WordPress or WooCommerce theme.

✍️ Describe the bug

Even with add_filter( 'action_scheduler_use_async_request_runner', '__return_false', PHP_INT_MAX ) applied in a must-use plugin, Meta for WooCommerce continues dispatching async HTTP loopback requests to admin-ajax.php?action=as_async_request_queue_runner. The filter is confirmed loading correctly via wp plugin list --type=mustuse.
This caused 35+ concurrent MySQL connections all executing the same slow query simultaneously, driving server load average to 40+ on an 8-core server and making the site unresponsive.
The plugin also generates extremely high Action Scheduler volume — approximately 200,000+ rows per day — primarily from facebook_for_woocommerce_5_minute_heartbeat firing every 5 minutes and hourly promotions feed regeneration chains (chain_start, chain_batch, chain_end).

🚶‍♀️ Steps to reproduce

  1. Install Meta for WooCommerce 3.5.18 on a WooCommerce store with server-side cron (DISABLE_WP_CRON = true)
  2. Add add_filter( 'action_scheduler_use_async_request_runner', '__return_false', PHP_INT_MAX ) to a must-use plugin
  3. Monitor Nginx access logs for admin-ajax.php?action=as_async_request_queue_runner
  4. Monitor MySQL processlist for concurrent SELECT COUNT(DISTINCT claim_id) FROM wp_actionscheduler_actions queries
  5. Observe that async runner requests continue despite the filter, and concurrent MySQL queries pile up

✔️ Expected behavior

add_filter( 'action_scheduler_use_async_request_runner', '__return_false' ) returning false should completely prevent Meta for WooCommerce from dispatching async loopback requests to the queue runner endpoint. When DISABLE_WP_CRON is true and a server cron is in use, no async HTTP requests should be dispatched.
Additionally, the volume of Action Scheduler rows generated (~200K rows/day on a store with 29 products) seems disproportionate and worth reviewing, particularly the 5-minute heartbeat which alone generates ~288 rows/day.
Workaround required: Had to explicitly intercept the AJAX endpoint in a must-use plugin to prevent MySQL overload:

`add_action( 'wp_ajax_nopriv_as_async_request_queue_runner', function() {
    wp_die( '', '', [ 'response' => 403 ] );
}, 0 );
add_action( 'wp_ajax_as_async_request_queue_runner', function() {
    wp_die( '', '', [ 'response' => 403 ] );
}, 0 );

🗃 Logs

Details

Environment:

  • Meta for WooCommerce: 3.5.18 (latest)
  • WooCommerce: 10.5.2
  • WordPress: 6.9.1
  • PHP: 8.3.30
  • MySQL: 8.4.8
  • Server: AlmaLinux, cPanel/WHM, 8 CPU cores

MySQL processlist showing 35+ concurrent stuck queries (load average 40.20):

| xyz_db2 | Query | 73 | executing | SELECT COUNT(DISTINCT claim_id) FROM wp_actionscheduler_actions WHERE claim_id != 0 AND status IN ( 'pending', 'in-progress') |
| xyz_db2 | Query | 72 | executing | SELECT COUNT(DISTINCT claim_id) FROM wp_actionscheduler_actions WHERE claim_id != 0 AND status IN ( 'pending', 'in-progress') |
| xyz_db2 | Query | 69 | executing | SELECT COUNT(DISTINCT claim_id) FROM wp_actionscheduler_actions WHERE claim_id != 0 AND status IN ( 'pending', 'in-progress') |
-- (35+ identical rows)

Nginx access log showing async runner requests continuing despite filter:

 [01/Mar/2026] "POST /wp-admin/admin-ajax.php?action=as_async_request_queue_runner&nonce=xxx HTTP/1.1" 200
-- (90,672 requests from server's own IP in a single log file)

Action Scheduler table volume (primarily from this plugin):

complete | 801,804  (all within 30 days, majority within 2 days)
pending  |     206

Top hooks by volume:

facebook_for_woocommerce_5_minute_heartbeat       -- every 5 minutes
facebook_for_woocommerce_hourly_heartbeat         -- every hour  
wc_facebook_regenerate_feed_promotions            -- every hour + spawns chain jobs
facebook_for_woocommerce/jobs/promotions_feed_generator/chain_start
facebook_for_woocommerce/jobs/promotions_feed_generator/chain_batch
facebook_for_woocommerce/jobs/promotions_feed_generator/chain_end

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions