BUG > No lock/mutex on transient cache refresh

Subject: No lock/mutex on transient cache refresh in Mfn_Dashboard/Mfn_Api — causes concurrent PHP-FPM workers to make redundant simultaneous outbound API calls under load

Betheme 28.5.10

Site: imaginity.com

Environment: WordPress 7.1.2, PHP 8.3.33, WP Rocket + WPML + Imagify active, PHP-FPM (2 CPU cores)

Summary:

Mfn_Dashboard::__construct() (in functions/admin/class-mfn-dashboard.php) calls get_promo_version() and get_expiration() on every request that instantiates the class, which our stack traces show happening on plain admin-ajax.php and admin.php requests — including ones triggered by unrelated background tasks (e.g. other plugins' async queue dispatches). Similarly, Mfn_Api::get_update_version() and get_update_pricing() run from the same constructor chain.

Each of these follows the pattern:


php

$version = get_site_transient( 'betheme_xxx' );
if ( ! $version ) {
    $version = $this->refresh_xxx(); // makes the actual outbound HTTP call
}

This correctly avoids calling out to muffingroup.com on every request — but only while the transient is valid. The moment a transient expires, there is no lock around refresh_xxx(). If multiple PHP-FPM workers process concurrent requests in that same window (which is common under real traffic, since admin-ajax.php is hit constantly by other plugins), every one of them independently sees the cache miss and independently fires its own outbound curl_exec() call to the same Muffin Group endpoint at the same time.

Evidence:

We caught this live via PHP-FPM's slow-request log (request_slowlog_timeout lowered to 2s to capture it). Within a single ~5-minute window we saw three separate PHP-FPM worker PIDs simultaneously blocked in curl_exec(), all inside remote_get_pricing() / remote_get_promo_version() / remote_get_version(), all originating from Mfn_Dashboard::__construct() → functions.php:228 → wp-settings.php:747. Live FPM status showed those workers' request durations climbing past 1-2.4 seconds while stuck. Individually, each Muffin Group endpoint responds in ~0.5s when tested directly — the slowdown is entirely from redundant concurrent calls stacking up, not from your API being slow.

Impact:

On any moderately busy or CPU-constrained server, this produces bursts of simultaneous multi-second PHP-FPM worker stalls every time one of these transients expires (TTLs observed: 6 hours for update version, 1 day for promo version and pricing, 1 week for expiration) — i.e., a recurring, predictable performance hit, worse on lower-resource hosting where several concurrent curl/TLS operations compete for limited CPU.

Suggested fix:

Add a short-lived (e.g. 30-60 second) "refreshing" lock transient around each refresh_xxx() function: the first request to see a cache miss sets the lock and performs the real fetch; any other concurrent request that finds the lock set simply returns the last cached value (or the existing -1 fallback sentinel your code already uses for failed fetches) instead of also calling the API. This is a standard cache-stampede guard and would be a minimal, low-risk change to class-mfn-dashboard.php and class-mfn-api.php.

We've applied a workaround on our end via a small mu-plugin (using WordPress's pre_http_request filter to deduplicate concurrent calls to muffingroup.com) so this isn't currently affecting us, but flagging it since it would affect any customer under similar concurrent load.

Happy to share the exact PHP-FPM stack traces or our workaround code if useful for reproducing this.

Comments

  • Hello,

    We would like to politely point out that we will no longer be responding to automatically generated messages from AI agents. We strictly provide real human support to resolve actual user issues.

    If you encounter any operational problems while using our theme, please describe the issue you are experiencing, and we will gladly fix it. Please refrain from pasting automated code analysis generated by AI tools.


    Best regards

  • Thank you Phil for your reply

    It seems the problem was more related to object-cache and WPML flushing it. We are still investigating the issue

    The situation is probably not Betheme related, sorry for the false report

    Thank you for your kind support, as always

    Best regards

Sign In or Register to comment.
This website uses cookies

We use cookies to personalise content and ads, to provide social media features and to analyse our traffic. We also share information about your use of our site with our social media, advertising and analytics partners who may combine it with other information that you’ve provided to them or that they’ve collected from your use of their services.

Cookies are small text files that can be used by websites to make a user's experience more efficient.

The law states that we can store cookies on your device if they are strictly necessary for the operation of this site. For all other types of cookies we need your permission. This means that cookies which are categorized as necessary, are processed based on GDPR Art. 6 (1) (f). All other cookies, meaning those from the categories preferences and marketing, are processed based on GDPR Art. 6 (1) (a) GDPR.

This site uses different types of cookies. Some cookies are placed by third party services that appear on our pages.

You can at any time change or withdraw your consent from the Cookie Declaration on our website.

Learn more about who we are, how you can contact us and how we process personal data in our Privacy Policy.

Please state your consent ID and date when you contact us regarding your consent.