PluginProbe ʕ •ᴥ•ʔ
WP STAGING – WordPress Backup, Restore, Migration & Clone / 3.3.1
WP STAGING – WordPress Backup, Restore, Migration & Clone v3.3.1
4.9.1 4.9.0 4.8.1 trunk 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.10.0 3.2.0 3.3.1 3.3.2 3.3.3 3.4.1 3.4.3 3.5.0 3.6.0 3.7.1 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.8.7 3.9.0 3.9.1 3.9.2 3.9.3 3.9.4 4.0.0 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.0 4.7.0 4.7.1 4.7.2 4.7.3 4.8.0
wp-staging / Framework / Traits / ResourceTrait.php
wp-staging / Framework / Traits Last commit date
ArrayableTrait.php 5 years ago BenchmarkTrait.php 2 years ago BooleanTransientTrait.php 5 years ago DatabaseSearchReplaceTrait.php 2 years ago DbRowsGeneratorTrait.php 3 years ago DeveloperTimerTrait.php 4 years ago FileScanToCacheTrait.php 2 years ago HydrateTrait.php 2 years ago MaintenanceTrait.php 5 years ago MemoryExhaustTrait.php 2 years ago MySQLRowsGeneratorTrait.php 2 years ago NoticesTrait.php 2 years ago PropertyConstructor.php 5 years ago ResourceTrait.php 2 years ago
ResourceTrait.php
343 lines
1 <?php
2
3 namespace WPStaging\Framework\Traits;
4
5 use WPStaging\Core\WPStaging;
6 use WPStaging\Framework\Facades\Hooks;
7
8 trait ResourceTrait
9 {
10 /** @var int|null */
11 protected $timeLimit;
12
13 protected $resourceTraitSettings;
14 protected $executionTimeLimit;
15 protected $memoryLimit;
16 protected $scriptMemoryLimit;
17
18 public static $defaultMaxExecutionTimeInSeconds = 30;
19 public static $executionTimeGapInSeconds = 5;
20
21 // Set lower maximum execution time for backup restore to avoid 504 errors in large database
22 public static $backupRestoreMaxExecutionTimeInSeconds = 10;
23
24 /** @var bool Whether this request is taking place in the context of a unit test. */
25 protected $isUnitTest;
26
27 /** @var bool If it is a unit test, whether to allow resource checks. */
28 protected $allowResourceCheckOnUnitTests;
29
30 /**
31 * @return bool
32 */
33 public function isThreshold()
34 {
35 if ($this->isUnitTest() && !$this->allowResourceCheckOnUnitTests) {
36 return false;
37 }
38
39 $isMemoryLimit = $this->isMemoryLimit();
40 $isTimeLimit = $this->isTimeLimit();
41
42 if (defined('WPSTG_DEBUG') && WPSTG_DEBUG) {
43 if ($isTimeLimit || $isMemoryLimit) {
44 \WPStaging\functions\debug_log('isThreshold: ' . wp_json_encode(['class' => __CLASS__, 'isTimeLimit' => $isTimeLimit, 'isMemoryLimit' => $isMemoryLimit], JSON_UNESCAPED_SLASHES));
45 }
46 }
47
48 if ($isMemoryLimit) {
49 return true;
50 }
51
52 if ($isTimeLimit) {
53 return true;
54 }
55
56 return false;
57 }
58
59 /**
60 * @return bool
61 */
62 public function isDatabaseRestoreThreshold()
63 {
64 return $this->isMemoryLimit() || $this->isDatabaseRestoreTimeLimit();
65 }
66
67 /**
68 * @return bool
69 */
70 public function isMaxExecutionThreshold()
71 {
72 return $this->isMemoryLimit() || $this->isMaxExecutionTimeoutLimit();
73 }
74
75 /**
76 * @see \Codeception\Module\WPLoader::_getConstants
77 *
78 * @return bool Whether this request is in the context of a unit test.
79 */
80 protected function isUnitTest()
81 {
82 if (isset($this->isUnitTest)) {
83 return $this->isUnitTest;
84 }
85
86 $this->isUnitTest = defined('WPCEPT_ISOLATED_INSTALL');
87
88 return $this->isUnitTest;
89 }
90
91 /**
92 * @return float
93 */
94 protected function getRunningTime()
95 {
96 return microtime(true) - WPStaging::$startTime;
97 }
98
99 /**
100 * @return bool
101 */
102 public function isMemoryLimit()
103 {
104 return $this->getScriptMemoryLimit() <= $this->getMemoryUsage();
105 }
106
107 /**
108 * @return bool
109 */
110 public function isTimeLimit()
111 {
112 $timeLimit = $this->findExecutionTimeLimit();
113
114 if (isset($this->timeLimit)) {
115 $timeLimit = $this->timeLimit;
116 }
117
118 return $this->getRunningTime() > $timeLimit;
119 }
120
121 /**
122 * @return bool
123 */
124 public function isDatabaseRestoreTimeLimit()
125 {
126 $timeLimit = (int)apply_filters('wpstg.resourceTrait.backupRestoreMaxExecutionTimeInSeconds', static::$backupRestoreMaxExecutionTimeInSeconds);
127 return $this->getRunningTime() > $timeLimit;
128 }
129
130 /**
131 * @return bool
132 */
133 public function isMaxExecutionTimeoutLimit()
134 {
135 return $this->getRunningTime() > $this->findExecutionTimeLimit(true);
136 }
137
138 /**
139 * Returns the maximum allowed execution time limit.
140 * The minimum needs to be 10seconds!
141 * @see https://github.com/wp-staging/wp-staging-pro/pull/1492
142 *
143 * @param bool $useMaxTimeout
144 *
145 * @return float|int
146 */
147 public function findExecutionTimeLimit($useMaxTimeout = false)
148 {
149 // Early bail: Cache
150 if (isset($this->executionTimeLimit)) {
151 return $this->executionTimeLimit;
152 }
153
154 $phpMaxExecutionTime = $this->getPhpMaxExecutionTime();
155 $cpuBoundMaxExecutionTime = $this->getCpuBoundMaxExecutionTime();
156
157 // Use the max execution time limit for CPU bound tasks like tables renaming
158 if ($useMaxTimeout) {
159 $this->executionTimeLimit = max(min($phpMaxExecutionTime - static::$executionTimeGapInSeconds, $phpMaxExecutionTime * 0.8), 10);
160
161 // Internal Use only. Allow overwriting of the max execution time limit for testing database rename task.
162 $this->executionTimeLimit = (int)Hooks::applyFilters('wpstg.tests.databaseRenameTask', $this->executionTimeLimit);
163
164 return $this->executionTimeLimit;
165 }
166
167 // TODO don't overwrite when CLI / SAPI and / or add setting to not overwrite for devs
168 if (!$cpuBoundMaxExecutionTime || $cpuBoundMaxExecutionTime > static::$defaultMaxExecutionTimeInSeconds) {
169 $cpuBoundMaxExecutionTime = static::$defaultMaxExecutionTimeInSeconds;
170 }
171
172 // Never go over PHP own execution time limit, if set.
173 if ($phpMaxExecutionTime > 0) {
174 $cpuBoundMaxExecutionTime = min($phpMaxExecutionTime, $cpuBoundMaxExecutionTime);
175 }
176
177 // Set a max of 30 seconds to avoid NGINX 504 timeouts that are beyond PHP's control, with a minimum of 10 seconds
178 $this->executionTimeLimit = max(min($cpuBoundMaxExecutionTime - static::$executionTimeGapInSeconds, 30), 10);
179
180 // Allow overwriting of the max execution time limit.
181 // Important: Use a value lower than the actual PHP limit. (reduce it by 10seconds or more). Also adjust the nginx/php timeout limit
182 $this->executionTimeLimit = (int)apply_filters('wpstg.resources.executionTimeLimit', $this->executionTimeLimit);
183
184 // Allow disabling of the execution time limit
185 if ((bool)apply_filters('wpstg.resources.ignoreTimeLimit', false)) {
186 $this->executionTimeLimit = PHP_INT_MAX;
187 }
188
189 return $this->executionTimeLimit;
190 }
191
192 /**
193 * @param bool $realUsage
194 *
195 * @return int
196 */
197 protected function getMemoryUsage($realUsage = true)
198 {
199 return memory_get_usage($realUsage);
200 }
201
202 /**
203 * @param bool $realUsage
204 *
205 * @return int
206 */
207 protected function getMemoryPeakUsage($realUsage = true)
208 {
209 return memory_get_peak_usage($realUsage);
210 }
211
212 /**
213 * @return int|null
214 */
215 public function getTimeLimit()
216 {
217 if (!isset($this->timeLimit)) {
218 $this->timeLimit = $this->findExecutionTimeLimit();
219 }
220
221 return $this->timeLimit;
222 }
223
224 /**
225 * @param int|null $timeLimit
226 */
227 public function setTimeLimit($timeLimit)
228 {
229 $this->timeLimit = $timeLimit;
230 }
231
232 /**
233 * @param bool $isAllowed True to check resources on unit tests. False to not check.
234 */
235 public function resourceCheckOnUnitTests($isAllowed)
236 {
237 $this->allowResourceCheckOnUnitTests = $isAllowed;
238 }
239
240 /**
241 * Returns the current PHP memory limit in bytes.
242 *
243 * @return int
244 */
245 protected function getMaxMemoryLimit()
246 {
247 // Early bail: Cache
248 if (isset($this->memoryLimit)) {
249 return $this->memoryLimit;
250 }
251
252 $memoryLimit = wp_convert_hr_to_bytes(ini_get('memory_limit'));
253
254 // No memory limit
255 if ($memoryLimit == -1 || $memoryLimit < 0) {
256 $memoryLimit = 256 * MB_IN_BYTES;
257 }
258
259 // Allow custom overwriting
260 $this->memoryLimit = apply_filters('wpstg.resources.memoryLimit', $memoryLimit);
261
262 // Unexpected memory limit after filter and also make sure it is never below 64MB
263 if (!is_int($this->memoryLimit) || $this->memoryLimit < (64 * MB_IN_BYTES)) {
264 $this->memoryLimit = 64 * MB_IN_BYTES;
265 }
266
267 // Make sure it never exceeds 256MB
268 $this->memoryLimit = (min($this->memoryLimit, 256 * MB_IN_BYTES));
269
270 // Allow disabling the memory limit
271 if ((bool)apply_filters('wpstg.resources.ignoreMemoryLimit', false)) {
272 $this->memoryLimit = PHP_INT_MAX;
273 }
274
275 return $this->memoryLimit;
276 }
277
278 /**
279 * Returns the actual script memory limit.
280 *
281 * @return int|float The script memory limit, by definition less then the maximum memory limit.
282 */
283 protected function getScriptMemoryLimit()
284 {
285 // Early bail: Cache
286 if (isset($this->scriptMemoryLimit)) {
287 return $this->scriptMemoryLimit;
288 }
289
290 // 80% of max memory limit
291 return $this->scriptMemoryLimit = $this->getMaxMemoryLimit() * 0.8;
292 }
293
294 /**
295 * Returns the max execution time value as bound by the "CPU Load" setting.
296 *
297 * @param string|null $cpuLoadSetting Either a specific CPU Load setting to
298 * return the max execution time for, or
299 * `null` to read the current CPU Load
300 * value from the Settings.
301 *
302 * @return int The max execution time as bound by the CPU Load setting.
303 */
304 protected function getCpuBoundMaxExecutionTime($cpuLoadSetting = null)
305 {
306 // Early bail: Cache
307 if (!isset($this->resourceTraitSettings)) {
308 $this->resourceTraitSettings = json_decode(json_encode(get_option('wpstg_settings', [])));
309 }
310
311 if ($cpuLoadSetting === null) {
312 $cpuLoadSetting = isset($this->resourceTraitSettings->cpuLoad) ? $this->resourceTraitSettings->cpuLoad : 'medium';
313 }
314
315 $execution_gap = static::$executionTimeGapInSeconds;
316 switch ($cpuLoadSetting) {
317 case 'low':
318 $cpuBoundMaxExecutionTime = 10 + $execution_gap;
319 break;
320 case 'medium':
321 default:
322 $cpuBoundMaxExecutionTime = 20 + $execution_gap;
323 break;
324 case 'high':
325 $cpuBoundMaxExecutionTime = 25 + $execution_gap;
326 break;
327 }
328
329 return $cpuBoundMaxExecutionTime;
330 }
331
332 /**
333 * Returns the max execution time as set in PHP ini settings.
334 *
335 * @return int The PHP max execution time in seconds. Note that `0` and `-1` would
336 * both indicate there is no time limit set.
337 */
338 private function getPhpMaxExecutionTime()
339 {
340 return (int)ini_get('max_execution_time');
341 }
342 }
343