Summary
The SDK issues every API request with a 60s timeout (and a 10s connect timeout) in Freemius_Api_WordPress::MakeStaticRequest() (includes/sdk/FreemiusWordPress.php):
$pWPRemoteArgs = array(
'method' => strtoupper( $pMethod ),
'connect_timeout' => 10,
'timeout' => 60,
...
);
On hosts with a small PHP-FPM worker pool, if api.freemius.com is slow or unreachable, these synchronous (blocking) wp_remote_request calls can each hold a PHP worker for up to 60s. Background calls that run unattended (the plugin update check via pre_set_site_transient_update_plugins, and the daily data_sync cron) then accumulate stuck workers and can exhaust the pool. The result is wp-admin returning 503 Service Unavailable, while the (full-page-cached) front end keeps working.
This is amplified by the fact that a non-404 API error is not negatively cached: FS_Api::get() returns without caching on error (includes/class-fs-api.php), so subsequent requests re-attempt the slow call instead of backing off.
Why 60s seems too high for today's environment
In normal operation the API responds in well under a second. A 60s ceiling only matters in pathological cases, and in exactly those cases it is actively harmful: it turns a slow upstream into site-wide admin worker exhaustion. A few seconds of slack is plenty for a healthy request.
Suggestion
- Lower the default request timeout to something sane, e.g. 10 to 20 seconds.
- Ideally differentiate: a short timeout for background / idempotent GETs (update checks, sync cron) versus a longer one only for user-initiated POSTs (activation, opt-in, large syncs), where a human is waiting and a slower response is tolerable.
- And/or make the timeout filterable, e.g.
apply_filters( 'fs_api_request_timeout', $timeout, $method, $canonized_path ), so integrators can tune it without patching the vendored SDK.
- Consider briefly negative-caching transient API failures so a degraded
api.freemius.com is not retried on every request.
Observed
WordPress 7.0, a plugin bundling the SDK, managed host with a small FPM pool: admin returned 503 while the cached front end stayed up; deactivating the plugin (which removes the SDK) immediately restored the admin.
References
includes/sdk/FreemiusWordPress.php - MakeStaticRequest(), 'connect_timeout' => 10, 'timeout' => 60
includes/class-fs-api.php - get(): the non-404 error path returns without caching
Happy to open a PR if you are open to a direction here.
Summary
The SDK issues every API request with a 60s timeout (and a 10s connect timeout) in
Freemius_Api_WordPress::MakeStaticRequest()(includes/sdk/FreemiusWordPress.php):On hosts with a small PHP-FPM worker pool, if
api.freemius.comis slow or unreachable, these synchronous (blocking)wp_remote_requestcalls can each hold a PHP worker for up to 60s. Background calls that run unattended (the plugin update check viapre_set_site_transient_update_plugins, and the dailydata_synccron) then accumulate stuck workers and can exhaust the pool. The result iswp-adminreturning 503 Service Unavailable, while the (full-page-cached) front end keeps working.This is amplified by the fact that a non-404 API error is not negatively cached:
FS_Api::get()returns without caching on error (includes/class-fs-api.php), so subsequent requests re-attempt the slow call instead of backing off.Why 60s seems too high for today's environment
In normal operation the API responds in well under a second. A 60s ceiling only matters in pathological cases, and in exactly those cases it is actively harmful: it turns a slow upstream into site-wide admin worker exhaustion. A few seconds of slack is plenty for a healthy request.
Suggestion
apply_filters( 'fs_api_request_timeout', $timeout, $method, $canonized_path ), so integrators can tune it without patching the vendored SDK.api.freemius.comis not retried on every request.Observed
WordPress 7.0, a plugin bundling the SDK, managed host with a small FPM pool: admin returned 503 while the cached front end stayed up; deactivating the plugin (which removes the SDK) immediately restored the admin.
References
includes/sdk/FreemiusWordPress.php-MakeStaticRequest(),'connect_timeout' => 10,'timeout' => 60includes/class-fs-api.php-get(): the non-404 error path returns without cachingHappy to open a PR if you are open to a direction here.