From dda39cfad4dcea75dd24ea918f6968eb88947ba3 Mon Sep 17 00:00:00 2001 From: Alda Vigdis Date: Fri, 19 Jun 2026 00:55:12 +0200 Subject: [PATCH 1/2] Cron: Make response flushing optional A client's site has been having difficulties running wp-cron jobs. Within 1 second, the wp-cron process get killed. This usually happens in unsuspecting places such as the middle of an SQL request or REST API call, but almost always within the first 1-2 seconds. However, the exact same functions can be run as a foreground process in PHP without issue. This has caused issues with Action Scheduler, WooCommerce lookup tables have become out of sync and my own ERP sync solution for WordPress stopped sync. Running the site locally in PHP-FPM does not reproduce the issue. I have traced the issue to wp-cron calling `litespeed_finish_request()` when that function is available. However in this case, the LSPHP web server seems to kill the resulting child process within a second from spawning it. This also seems to cause some memory leaks and swapping in the LSPHP web server. The issue has been mended on the client's site by commenting out the following code block in wp-cron.php:i ```php if ( function_exists( 'fastcgi_finish_request' ) ) { fastcgi_finish_request(); } elseif ( function_exists( 'litespeed_finish_request' ) ) { litespeed_finish_request(); } ``` In order to prevent this and similar issues, I suggest adding a new config constant; `WP_CRON_FLUSH`, defaulting to true to optionally enable flushing wp-cron response data and continuing in the background. I also suggest `WP_CRON_IGNORE_ABORT`, defaulting to true to indicate whether or not to call `ignore_user_abort( true )` as it may cause similar issues. It has taken me a while to trace the issue to wp-cron and LSPHP as this had all the symptoms of a memory constrained web server. I have communicated this issue with the relevant hosting provider as I am uncertain if this is isolated to their hosting packages or if this is more widespread. However, I have concluded that is warrants a patch to the WP Core to make flushing response data and spawning a child process using `fastcgi_finish_reques()` or `litespeed_finish_request()` optional. An added benefit to this is this makes it easier and more straightforward to debug wp-cron jobs, as `WP_DEBUG_DISPLAY` can be set to true along with `WP_CRON_FLUSH` to false. In addition, tasks that should take more than a couple of seconds but crash can be identified using browser tools or cron without running something like New Relic to identify issues. I don't expect this to require unit tests as this concerns specific application servers. The issue has been mended by commenting out the following code block in wp-cron.php: --- src/wp-cron.php | 16 ++++++++++------ src/wp-includes/default-constants.php | 24 ++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/wp-cron.php b/src/wp-cron.php index 417dcce375849..d068f7ab391a8 100644 --- a/src/wp-cron.php +++ b/src/wp-cron.php @@ -16,18 +16,22 @@ * @package WordPress */ -ignore_user_abort( true ); - if ( ! headers_sent() ) { header( 'Expires: Wed, 11 Jan 1984 05:00:00 GMT' ); header( 'Cache-Control: no-cache, must-revalidate, max-age=0' ); } +if ( defined( 'WP_CRON_IGNORE_ABORT' ) && true === WP_CRON_IGNORE_ABORT ) { + ignore_user_abort( true ); +} + // Don't run cron until the request finishes, if possible. -if ( function_exists( 'fastcgi_finish_request' ) ) { - fastcgi_finish_request(); -} elseif ( function_exists( 'litespeed_finish_request' ) ) { - litespeed_finish_request(); +if ( defined( 'WP_CRON_FLUSH' ) && true === WP_CRON_FLUSH ) { + if ( function_exists( 'fastcgi_finish_request' ) ) { + fastcgi_finish_request(); + } elseif ( function_exists( 'litespeed_finish_request' ) ) { + litespeed_finish_request(); + } } if ( ! empty( $_POST ) || defined( 'DOING_AJAX' ) || defined( 'DOING_CRON' ) ) { diff --git a/src/wp-includes/default-constants.php b/src/wp-includes/default-constants.php index acfc878fb7138..61c79cf7fa7c9 100644 --- a/src/wp-includes/default-constants.php +++ b/src/wp-includes/default-constants.php @@ -398,6 +398,30 @@ function wp_functionality_constants() { if ( ! defined( 'WP_CRON_LOCK_TIMEOUT' ) ) { define( 'WP_CRON_LOCK_TIMEOUT', MINUTE_IN_SECONDS ); } + + /** + * Wether or not to ignore user abort when running wp-cron + * + * @see https://www.php.net/manual/en/function.ignore-user-abort.php + */ + if ( ! defined( 'WP_CRON_IGNORE_ABORT' ) ) { + define( 'WP_CRON_IGNORE_ABORT', true ); + } + + /** + * Flush wp-cron response data + * + * Wether or not to flush wp-cron response data and close the HTTP request + * before continuing in the background. This invokes a child process in + * PHP-FPM and LSPHP and closes the HTTP connection to the client. + * + * @see https://www.php.net/manual/en/function.ignore-user-abort.php + * @see https://www.php.net/manual/en/function.fastcgi-finish-request.php + * @see https://www.php.net/manual/en/function.litespeed-finish-request.php + */ + if ( ! defined( 'WP_CRON_FLUSH' ) ) { + define( 'WP_CRON_FLUSH', true ); + } } /** From 764ad5d2751f8777e2c78ba5bcbab39597fb4a36 Mon Sep 17 00:00:00 2001 From: Alda Vigdis Date: Fri, 19 Jun 2026 01:29:41 +0200 Subject: [PATCH 2/2] Switching see PHPDoc tags to link --- src/wp-includes/default-constants.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wp-includes/default-constants.php b/src/wp-includes/default-constants.php index 61c79cf7fa7c9..ebad0cf4d01ef 100644 --- a/src/wp-includes/default-constants.php +++ b/src/wp-includes/default-constants.php @@ -415,9 +415,9 @@ function wp_functionality_constants() { * before continuing in the background. This invokes a child process in * PHP-FPM and LSPHP and closes the HTTP connection to the client. * - * @see https://www.php.net/manual/en/function.ignore-user-abort.php - * @see https://www.php.net/manual/en/function.fastcgi-finish-request.php - * @see https://www.php.net/manual/en/function.litespeed-finish-request.php + * @link https://www.php.net/manual/en/function.ignore-user-abort.php + * @link https://www.php.net/manual/en/function.fastcgi-finish-request.php + * @link https://www.php.net/manual/en/function.litespeed-finish-request.php */ if ( ! defined( 'WP_CRON_FLUSH' ) ) { define( 'WP_CRON_FLUSH', true );