PluginProbe
Powered Cache – Caching and Optimization for WordPress – Easily Improve PageSpeed & Web Vitals Score / trunk
Powered Cache – Caching and Optimization for WordPress – Easily Improve PageSpeed & Web Vitals Score vtrunk
trunk 1.0 1.0.1 1.1 1.1.1 1.1.2 1.2 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 2.0 2.0.1 2.0.2 2.0.3 2.0.4 2.1 2.1.1 2.1.2 2.2 2.2.1 All 69 releases
powered-cache / includes / classes / Async / CachePreloader.php

CachePreloader.php in Powered Cache – Caching and Optimization for WordPress – Easily Improve PageSpeed & Web Vitals Score trunk, at includes/classes/Async/CachePreloader.php

231 lines 5.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Background process for cache preloading
4 *
5 * @package PoweredCache
6 */
7
8 namespace PoweredCache\Async;
9
10 use PoweredCache\Preloader;
11 use function PoweredCache\Utils\detect_cpu_cores;
12 use function PoweredCache\Utils\is_url_cached;
13 use \Powered_Cache_WP_Background_Process as Powered_Cache_WP_Background_Process;
14
15 /**
16 * Class CachePreloader
17 */
18 class CachePreloader extends Powered_Cache_WP_Background_Process {
19
20 /**
21 * Plugin settings
22 *
23 * @var $settings
24 */
25 protected $settings;
26
27 /**
28 * string
29 *
30 * @var $action
31 */
32 protected $action = 'powered_cache_preload';
33
34 /**
35 * Supported preloading options
36 * Options are the key of plugin settings
37 *
38 * @return array
39 */
40 public function get_supported_options() {
41 return [
42 'preload_homepage',
43 'preload_public_posts',
44 'preload_public_tax',
45 ];
46 }
47
48 /**
49 * Task
50 *
51 * Perform Preload Tasks
52 *
53 * @param mixed $item Queue item to iterate over
54 *
55 * @return mixed
56 */
57 protected function task( $item ) {
58 // Stop early if system load is too high
59 if ( ! $this->should_continue() ) {
60 \PoweredCache\Utils\log( 'Preload task aborted early due to system load' );
61 return $item;
62 }
63
64 $this->settings = \PoweredCache\Utils\get_settings();
65 $delay = absint( $this->settings['preload_request_interval'] ) * 1000000; // convert to microseconds
66
67 \PoweredCache\Utils\log( sprintf( 'Preloading..: %s', $item ) );
68
69 if ( filter_var( $item, FILTER_VALIDATE_URL ) ) {
70
71 if ( ! is_url_cached( $item, false, $this->settings['gzip_compression'] ) ) {
72 Preloader::preload_request( $item );
73 Preloader::wait( $delay );
74 }
75
76 // make the preload request by using mobile agent
77 if ( $this->settings['cache_mobile'] && $this->settings['cache_mobile_separate_file'] ) {
78 if ( ! is_url_cached( $item, true, $this->settings['gzip_compression'] ) ) {
79 Preloader::preload_request( $item, [ 'user-agent' => Preloader::mobile_user_agent() ] );
80 Preloader::wait( $delay );
81 }
82 }
83 }
84
85 \PoweredCache\Utils\log( sprintf( 'Preloaded...: %s', $item ) );
86
87 return false;
88 }
89
90
91 /**
92 * Complete
93 *
94 * Override if applicable, but ensure that the below actions are
95 * performed, or, call parent::complete().
96 */
97 protected function complete() { // phpcs:ignore Generic.CodeAnalysis.UselessOverridingMethod.Found
98 parent::complete();
99 }
100
101 /**
102 * Sometimes canceling a process is glitchy
103 * Try to cancel all items in the queue up to $max_attempt
104 */
105 public function cancel_process() {
106 $max_attempt = 5;
107 $cancelled = 0;
108 while ( ! parent::is_queue_empty() ) {
109 if ( $cancelled >= $max_attempt ) {
110 break;
111 }
112 parent::cancel();
113 $cancelled ++;
114 }
115 }
116
117 /**
118 * Whether the process running or not
119 *
120 * @return bool
121 */
122 public function is_process_running() { // phpcs:ignore Generic.CodeAnalysis.UselessOverridingMethod.Found
123 return parent::is_processing();
124 }
125
126 /**
127 * Determine if the background process should continue.
128 * Stops the process if server load is too high or spikes suddenly.
129 *
130 * @return bool
131 */
132 public function should_continue() {
133 $should_continue = parent::should_continue();
134 $halted_by_load = false;
135
136 $load = function_exists( 'sys_getloadavg' )
137 ? sys_getloadavg()
138 : [ 0.0, 0.0, 0.0 ];
139
140 $load_1min = isset( $load[0] ) ? (float) $load[0] : 0.0;
141 $load_5min = isset( $load[1] ) ? (float) $load[1] : 0.0;
142 $load_15min = isset( $load[2] ) ? (float) $load[2] : 0.0;
143
144 // Weighted average: gives slightly more weight to short-term load.
145 $weighted_load = ( $load_1min * 0.5 + $load_5min * 0.3 + $load_15min * 0.2 );
146
147 // Consider a spike if 1min load is significantly higher than longer-term averages.
148 $load_spike_detected = ( $load_1min > $load_5min * 2 || $load_5min > $load_15min * 2 );
149
150 // Fallback max load threshold
151 $default_max_load = 16.0;
152
153 /**
154 * Filter the max allowed server load before preloading pauses.
155 *
156 * @hook powered_cache_preloader_max_server_load
157 *
158 * @param {float} $default_max_load Default load threshold.
159 * @param {array} $load [1min, 5min, 15min] load averages.
160 *
161 * @return {float} Maximum allowed server load before preloading pauses.
162 * @since 3.6
163 */
164 $max_allowed_load = apply_filters(
165 'powered_cache_preloader_max_server_load',
166 $default_max_load,
167 $load
168 );
169
170 // Allow setting a custom maximum server load threshold.
171 if ( defined( 'POWERED_CACHE_PRELOADER_MAX_SERVER_LOAD' ) && is_numeric( POWERED_CACHE_PRELOADER_MAX_SERVER_LOAD ) ) {
172 $max_allowed_load = (float) POWERED_CACHE_PRELOADER_MAX_SERVER_LOAD;
173 }
174
175 if ( $should_continue && ( $weighted_load > $max_allowed_load || $load_spike_detected ) ) {
176 \PoweredCache\Utils\log(
177 sprintf(
178 'Preload paused: server load too high or spike detected (1min: %.2f, 5min: %.2f, 15min: %.2f, weighted: %.2f, threshold: %.2f)',
179 $load_1min,
180 $load_5min,
181 $load_15min,
182 $weighted_load,
183 $max_allowed_load
184 )
185 );
186 $should_continue = false;
187 $halted_by_load = true;
188 }
189
190 /**
191 * Allow complete control over continuation logic.
192 *
193 * @hook powered_cache_preloader_should_continue
194 *
195 * @param bool $should_continue Whether to continue processing.
196 * @param bool $halted_by_load True if we halted due to load.
197 * @param array $load [1min, 5min, 15min] load averages.
198 * @param float $max_allowed_load Final load limit used for decision.
199 *
200 * @return bool Whether to continue processing.
201 * @since 3.6
202 */
203 return (bool) apply_filters(
204 'powered_cache_preloader_should_continue',
205 $should_continue,
206 $halted_by_load,
207 $load,
208 $max_allowed_load
209 );
210 }
211
212
213 /**
214 * Return an instance of the current class
215 *
216 * @return CachePreloader
217 * @since 2.0
218 */
219 public static function factory() {
220
221 static $instance;
222
223 if ( ! $instance ) {
224 $instance = new self();
225 }
226
227 return $instance;
228 }
229
230 }
231