Opened 6 years ago
Closed 4 years ago
#46465 closed enhancement (wontfix)
Implement logic that performs PHP code after connection with client is closed
Reported by: | umchal | Owned by: | |
---|---|---|---|
Milestone: | Priority: | normal | |
Severity: | normal | Version: | |
Component: | General | Keywords: | |
Focuses: | performance | Cc: |
Description
Hi there,
It would be great if this can be implemented in the core.
When I write plugins, it is almost unavoidable to perform extra database queries like accessing a custom database table, updating rows, and scheduling WP Cron actions etc. The problem is that it affects the page load time.
I've been wondering how this can be avoided and how the impact on the performance can be made minimum from the user experience perspective.
And I came up with a little technique using header('Content-Length: n')
and header('Connection: close' )
. Here is a working example plugin.
<?php /** * Plugin Name: Test - HTTP Connection Close */ class HTTPConnectionClose { public function __construct() { add_action( 'init', array( $this, 'startCapturing' ) ); add_action( 'shutdown', array( $this, 'endCapturing' ), PHP_INT_MIN ); } public function startCapturing() { ob_start(); } /** * @remark Should be called before `wp_ob_end_flush_all()`. */ public function endCapturing() { $_iOutputBufferLength = ( integer ) ob_get_length(); if ( ! headers_sent() ) { @header('Content-Length: ' . $_iOutputBufferLength ) ; @header('Connection: close' ); } if ( $_iOutputBufferLength ) { ob_end_flush(); } } } new HTTPConnectionClose;
Here are some examples that illustrate the benefits of this. You can add this code at the bottom of the above example plugin.
class Test_HTTPConnectionClose {
public function __construct() {
add_action( 'shutdown', array( $this, 'testHeavyTask' ), PHP_INT_MAX );
add_action( 'plugins_loaded', array( $this, 'testWPCronCheck' ) );
add_action( 'shutdown', array( $this, 'testWPCronSchedule' ) );
add_action( 'test_custom_action', array( $this, 'testCustomCronTask' ) );
}
public function testCustomCronTask() {
error_log( __METHOD__ . ': doing custom cron task.' );
}
/**
* This causes a couple of database queries. But with the above technique, this will not be seen during the page load.
*/
public function testWPCronSchedule() {
$_aArguments = array();
$_sActionName = 'test_custom_action';
if ( wp_next_scheduled( $_sActionName, $_aArguments ) ) {
return;
}
wp_schedule_single_event( time() + 5, $_sActionName, $_aArguments );
}
/**
* Checks registered WP Cron actions in the `shutdown` instead of `init` action
* to save a little load time in every single page load.
*/
public function testWPCronCheck() {
remove_action( 'init', 'wp_cron' );
if ( ! defined( 'DOING_CRON' ) ) {
add_action( 'shutdown', 'wp_cron' );
}
}
/**
* Simulates a heavy task which consumes 10 seconds. But with the above technique, the visitor do not feel any delay caused by this.
*/
public function testHeavyTask() {
sleep( 10 ); // sleep 10 seconds
error_log( 'done a heavy task which takes 10 seconds.' );
}
}
new Test_HTTPConnectionClose;
As you can see with the above testHeavyTask()
method, any heavy sub-routines can be done in the shutdown
action. Say, your plugin generates outputs and has a caching mechanism that schedules a task and calls wp-cron.php
when the output is expired. With this, even scheduling a WP Cron task will be no longer needed. The plugin can update the cache in the shutdown
action within the page load. This saves extra page load and also helps avoid PHP timeout issues in wp-cron.php
due to too many registered WP Cron actions. Needless to say, this helps for sites disabling WP Cron.
It's very short and should be technically feasible to implement. Not sure any side effects with this yet but maybe you guys can tell.
Hi @umchal and welcome to trac!
This ticket was discussed during a triage session today.
It was decided to close this ticket off and leave changes similar to your example code as plugin territory. While in many cases considering the site "sent" once the shutdown hook starts firing is safe, it's not guaranteed.
In
wp-cron.php
WordPress usesfastcgi_finish_request()
when possible on cron requests, you may wish to look at that with regard to a plugin.I'm going to close this off as
wontfix
, which is the term used on trac for tickets that won't have action taken on them.Thanks