Skip to content

Instantly share code, notes, and snippets.

@timnashcouk
Last active October 25, 2023 15:51
Show Gist options
  • Save timnashcouk/103c67e617fddf42e75d5004a35b4c0d to your computer and use it in GitHub Desktop.
Save timnashcouk/103c67e617fddf42e75d5004a35b4c0d to your computer and use it in GitHub Desktop.
Simple WordPress Memory Management
/**
* Memory Management for WordPress
* Provides different resources based on logged in user or not
*/
ini_set( 'memory_limit', '64M' ); // Set to the lowest possible value as this is the default.
$logged_in_user = false;
if( !empty( $_COOKIE ) ){ // $_COOKIE is super variable is always defined, but often empty
foreach ( $_COOKIE as $cookie_name => $cookie_value ) {
if ( 0 === strpos( $cookie_name, 'wordpress_logged_in_' ) ) { // Look for if cookie is present for logged in user
$logged_in_user = true;
break;
}
}
}
if( defined( 'WP_CLI') && WP_CLI ){ // A cookie won't be set for WP_CLI
$logged_in_user = true;
}
if( !$logged_in_user ){
define( 'WP_MEMORY_LIMIT', '64M' ); // Set to our lower boundary
define( 'WP_MAX_MEMORY_LIMIT', '64M' ); // Set to our lower boundary
set_time_limit( 12 ); // Set a max_execution time note it doesn't include time already spent https://www.php.net/manual/en/function.set-time-limit.php
}else{
define( 'WP_MEMORY_LIMIT', '128M' ); // Set to a reasonable value incase we have some admin things running.
define( 'WP_MAX_MEMORY_LIMIT', '256M' ); // Set to our upper boundary.
}
@timnashcouk
Copy link
Author

timnashcouk commented Oct 25, 2023

This is designed for instances where you have only a single PHP-FPM pool for both logged in and logged out users.

General Notes
WordPress wp_raise_memory_limits function which uses WP_MEMORY_LIMIT and WP_MAX_MEMORY_LIMIT uses the higher value from the above defines or the current ini_get memory_limit. So we have to set a lower limit if we want them to be treated as actual Maxmium memory limits see https://developer.wordpress.org/reference/functions/wp_raise_memory_limit/

Using the wordpress_logged_in_* cookie is no guarentee that a user is logged in, just that cookie is present. This is important because a bad actor could get around your memory limits simply by faking this cookie. However this is a case of trading off this potential vs the additional costs to validate users keeping in mind this code runs prior to us having any WordPress helper functions.

set_time_limit() this function defines a stop point, and we are using it to emulate the max_execution_time directive, however that number is the time from the point the function is called. So if it took 5 seconds to load and process wp_config.php then in the above scenario it would be anopther 12 before it's stopped meaning the entire time is 17seconds. Not if your max_execution time is set lower for example 15, then it will stop the script before our time limit.

Why might you do this
Let's say we don't have full control over our PHP-FPM pool and the host has been very generous with limits, we can get in a state where just a few visitors to the site can cause server issues with memory and CPU usage. Because they are hanging in poor code. Yes we should fix memory leaks and bottle necks, but the above gives the site a fighting chance. Basically if we have poor performance that is likely to cripple the site we want to bail early.

What is the better solution
Creating 2 PHP-FPM pools one for site visitors and one for logged in users.
Then define their own limits and workers (I briefly touch on how I do this https://timnash.co.uk/tailscale-caddy-for-better-admin-security/)
Having the logged in user pool static (if you have only 1-2 users) or with a minimum number of services started on dynamic and the frontend pool being ondemand or dynamic is a neat way to handle this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment