Commit f869547e533 for woocommerce
commit f869547e533f41e4ef216ad5c19fbcc4dd4cabf1
Author: Boro Sitnikovski <buritomath@gmail.com>
Date: Thu Mar 26 12:27:51 2026 +0100
[Performance] Add timeout to DataSourcePoller and skip redundant HTTP calls in wc_admin_daily (#63738)
* [Performance] Add timeout to DataSourcePoller and skip redundant HTTP calls in wc_admin_daily
- Add explicit 3s timeout to wp_remote_get() in DataSourcePoller::read_data_source()
to bound worker blocking on slow/failing remote endpoints (previously used WP default
of 5s with no upper bound enforcement).
- Remove redundant read_specs_from_data_sources() call in Events::do_wc_admin_daily()
for RemoteInboxNotifications; RemoteInboxNotificationsEngine::run() already calls
get_specs_from_data_sources() which fetches only when the transient is expired.
- Swap read_specs_from_data_sources() -> get_specs_from_data_sources() in
Events::possibly_refresh_data_source_pollers() for PaymentGatewaySuggestions and
RemoteFreeExtensions pollers so HTTP calls are skipped when transients are fresh.
- Remove now-unused RemoteInboxNotificationsDataSourcePoller import from Events.php.
* Changelog
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Set transient_expiry to DAY_IN_SECONDS for RemoteInboxNotificationsDataSourcePoller to preserve daily refresh
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
* Address review feedback: filter for timeout and schedule wc_admin_daily at 3am
- Add woocommerce_data_source_poller_timeout filter so site owners/extensions can adjust the HTTP timeout
- Schedule wc_admin_daily_wrapper at tomorrow_3am (consistent with cleanup_logs and cleanup_rate_limits) to reduce timeout impact during business hours
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
* Address review feedback: sanitize timeout filter, fix @since, skip empty transient on fetch failure
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
diff --git a/plugins/woocommerce/changelog/fix-wc-admin-daily-timeout-and-transient-guard b/plugins/woocommerce/changelog/fix-wc-admin-daily-timeout-and-transient-guard
new file mode 100644
index 00000000000..6974d9ed2af
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-wc-admin-daily-timeout-and-transient-guard
@@ -0,0 +1,4 @@
+Significance: patch
+Type: performance
+
+Add 3s timeout to DataSourcePoller HTTP calls and skip redundant remote fetches in wc_admin_daily when transients are fresh.
diff --git a/plugins/woocommerce/includes/class-woocommerce.php b/plugins/woocommerce/includes/class-woocommerce.php
index c7e83ce127c..ed5057f8966 100644
--- a/plugins/woocommerce/includes/class-woocommerce.php
+++ b/plugins/woocommerce/includes/class-woocommerce.php
@@ -1661,7 +1661,7 @@ final class WooCommerce {
as_schedule_recurring_action( $tomorrow_3am, DAY_IN_SECONDS, 'woocommerce_cleanup_rate_limits_wrapper', array(), 'woocommerce', true );
- as_schedule_recurring_action( time(), DAY_IN_SECONDS, 'wc_admin_daily_wrapper', array(), 'woocommerce', true );
+ as_schedule_recurring_action( $tomorrow_3am, DAY_IN_SECONDS, 'wc_admin_daily_wrapper', array(), 'woocommerce', true );
// Note: this is potentially redundant when the core package exists.
as_schedule_single_action( time() + 10, 'generate_category_lookup_table_wrapper', array(), 'woocommerce', true );
diff --git a/plugins/woocommerce/src/Admin/RemoteInboxNotifications/RemoteInboxNotificationsDataSourcePoller.php b/plugins/woocommerce/src/Admin/RemoteInboxNotifications/RemoteInboxNotificationsDataSourcePoller.php
index 414396e878a..4580948672a 100644
--- a/plugins/woocommerce/src/Admin/RemoteInboxNotifications/RemoteInboxNotificationsDataSourcePoller.php
+++ b/plugins/woocommerce/src/Admin/RemoteInboxNotifications/RemoteInboxNotificationsDataSourcePoller.php
@@ -42,7 +42,8 @@ class RemoteInboxNotificationsDataSourcePoller extends DataSourcePoller {
self::ID,
self::get_data_sources(),
array(
- 'spec_key' => 'slug',
+ 'spec_key' => 'slug',
+ 'transient_expiry' => DAY_IN_SECONDS,
)
);
}
diff --git a/plugins/woocommerce/src/Admin/RemoteSpecs/DataSourcePoller.php b/plugins/woocommerce/src/Admin/RemoteSpecs/DataSourcePoller.php
index d0812fd5ffa..00762fdeea4 100644
--- a/plugins/woocommerce/src/Admin/RemoteSpecs/DataSourcePoller.php
+++ b/plugins/woocommerce/src/Admin/RemoteSpecs/DataSourcePoller.php
@@ -174,6 +174,10 @@ abstract class DataSourcePoller {
$this->merge_specs( $specs_from_data_source, $specs, $url );
}
+ if ( count( $specs ) === 0 ) {
+ return false;
+ }
+
$specs_group = get_transient( $this->args['transient_name'] );
$specs_group = is_array( $specs_group ) ? $specs_group : array();
$locale = get_user_locale();
@@ -183,7 +187,7 @@ abstract class DataSourcePoller {
$specs_group,
$this->args['transient_expiry']
);
- return count( $specs ) !== 0;
+ return true;
}
/**
@@ -226,6 +230,13 @@ abstract class DataSourcePoller {
$url
),
array(
+ /**
+ * Filters the HTTP timeout (in seconds) used when fetching remote specs data sources.
+ *
+ * @since 10.8.0
+ * @param int $timeout Timeout in seconds. Default 3.
+ */
+ 'timeout' => max( 1, absint( apply_filters( 'woocommerce_data_source_poller_timeout', 3 ) ) ),
'user-agent' => 'WooCommerce/' . WC_VERSION . '; ' . home_url( '/' ),
)
);
diff --git a/plugins/woocommerce/src/Internal/Admin/Events.php b/plugins/woocommerce/src/Internal/Admin/Events.php
index da0923e6613..7b0f1ee6831 100644
--- a/plugins/woocommerce/src/Internal/Admin/Events.php
+++ b/plugins/woocommerce/src/Internal/Admin/Events.php
@@ -8,7 +8,6 @@ namespace Automattic\WooCommerce\Internal\Admin;
defined( 'ABSPATH' ) || exit;
use Automattic\WooCommerce\Admin\Features\Features;
-use Automattic\WooCommerce\Admin\RemoteInboxNotifications\RemoteInboxNotificationsDataSourcePoller;
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\RemoteInboxNotificationsEngine;
use Automattic\WooCommerce\Internal\Admin\Notes\CustomizeStoreWithBlocks;
use Automattic\WooCommerce\Internal\Admin\Notes\CustomizingProductCatalog;
@@ -143,7 +142,6 @@ class Events {
$this->possibly_refresh_data_source_pollers();
if ( $this->is_remote_inbox_notifications_enabled() ) {
- RemoteInboxNotificationsDataSourcePoller::get_instance()->read_specs_from_data_sources();
RemoteInboxNotificationsEngine::run();
}
@@ -253,7 +251,8 @@ class Events {
}
/**
- * Refresh transient for the following DataSourcePollers on wc_admin_daily cron job.
+ * Prime or fetch specs for the following DataSourcePollers on the wc_admin_daily cron job
+ * when their related transients are missing or expired:
* - PaymentGatewaySuggestionsDataSourcePoller
* - RemoteFreeExtensionsDataSourcePoller
*/
@@ -261,11 +260,11 @@ class Events {
$completed_tasks = get_option( 'woocommerce_task_list_tracked_completed_tasks', array() );
if ( ! in_array( 'payments', $completed_tasks, true ) && ! in_array( 'woocommerce-payments', $completed_tasks, true ) ) {
- PaymentGatewaySuggestionsDataSourcePoller::get_instance()->read_specs_from_data_sources();
+ PaymentGatewaySuggestionsDataSourcePoller::get_instance()->get_specs_from_data_sources();
}
if ( ! in_array( 'store_details', $completed_tasks, true ) && ! in_array( 'marketing', $completed_tasks, true ) ) {
- RemoteFreeExtensionsDataSourcePoller::get_instance()->read_specs_from_data_sources();
+ RemoteFreeExtensionsDataSourcePoller::get_instance()->get_specs_from_data_sources();
}
}
}