Why it’s may worth to debug requests in WordPress
Published: – Leave a comment
Recently, I had to fix a problem where a larger WordPress website couldn’t be accessed, since all PHP workers on the server were already being busy serving requests. That usually means one of two things: either we have many concurrent connections and the server has not enough resources to serve all of them in time, or serving the requests takes an unusual amount of time.
In our case, we could identify server-side that it was the latter. So what happened? After some digging, we found out that there was an unusual amount of requests against an API of a specific plugin we’re using. I won’t call its name since it doesn’t matter. Since we can only get the domain name itself on server-side, I decided to log all requests going out of the WP_Http
class of WordPress, so basically logging all requests going out of WordPress (except for ones directly using cURL or similar approaches).
Do the debugging
This can be done using this code:
\add_action(
'http_api_debug',
static function ( array|WP_Error $response, string $context, string $class, array $parsed_args, string $url ) {
\error_log( \print_r( $url . \PHP_EOL, true ), 3, __DIR__ . '/debug.log' );
},
10,
5
);
Code language: PHP (php)
That way, every URL of a request is logged into a debug.log
inside the directory this script is part of. Since this can be a rather large amount of data during a specific time span, you can also change the file name to include a part of a date and time, e.g. date and hour, to limit the data per file: '/debug_' . \wp_date( 'Y-m-d-H' ) . '.log'
Another problem occurs
At first, I saw many requests again another URL, also from a plugin – but a different one – checking for available credits for a given action. While I can understand such a behavior in general, since it was a multisite with a large set of websites, requesting the same data for all sites over and over again didn’t sound necessary to me. Especially since we use a pricing model with unlimited credits in this case.
So the first thing I did was to check where this data is stored (it was a generic transient) and make sure the data of the transient is always loaded from the primary site, so that it only has to be updated once a day for a single site. That worked well for some time, but in the end I changed it so that the check for “has exceeded quota” always just returns false. Since unlimited credits means there is no exceeding quota whatsoever.
I also contacted the support and they said it’s working as expected. It’s also worth mentioning that the plugin itself is not properly optimized for multisites.
And the initial problem?
With that the first problem being solved, the original one persists. At this time I also extended the debug log to see whether the request is coming from a cron job (\wp_doing_cron()
) or via Ajax (\wp_doing_ajax()
) or if it’s a request from the frontend or backend (\is_admin()
). Unfortunately, it were mostly frontend requests with just a few exceptions, always trying to check whether the license of the plugin is still active. Here, I contacted the support of the plugin, since it didn’t sound right for me that such requests were being made in the frontend. Additionally, they had a timeout of more than 30 seconds to “let their load balancing kick in”. Nice to know, but not so nice if the amount of requests is just being hold while their backend is load balancing, which binds so many PHP workers so that nearly no regular requests come through. And even if, the possibility is high that this request also requests their API.
The quick solution was similar to the first one: disable the license check by pretending that the license is already checked and active. Basically nulling the plugin (nulling is when such “call home” features to check and verify licenses are bypassed or disabled). I want to point out that this was no permanent solution and the licenses was a lifetime license, so it made no difference here, but it was a difference for the websites since they were accessible again.
It’s also worth mentioning that this issue with frontend requests has been resolved and since then, the license server is just requested on a daily bases from within the backend, as it should be.
Conclusion
Even if you have no actual problem at the moment with external requests of your WordPress installation, it may also happen to you. That’s why it’s definitely worth a try to log all outgoing requests for a couple of days and check for any suspicious behavior.